Feature/yousong text (#7487)

* notify: log with context info

* region: guests: log with context info

* region: hosts: log with context info

* region: misc: remove redundant log

* region: skus: use NewInternalServerError instead of NewGeneralError

* appsrv: dispatcher: preserve text id

* appsrv: dispatcher: remove commented-out code

* cloudcommon: db_dispatcher: note errors that won't be translated

* cloudcommon: db: rbac: preserve text id

* cloudcommon: caller: preserve text id

* treewide: fix fmt string

* region: guest_actions: preserve text id

* region: guest_actions: fix fmt string

* region: usages: fix fmt string

* mcclient: hosts: remove redundant return value

* cloudcommon: fetch: preserve text id

* region: guest_template: preserve text id

* cloudcommon: db: db_dispatcher: preserve text id

* region: guest_actions: preserve text id

* httperrors: add funcs for wrap lang tag into context

* vendor: golang.org/x/text

* httperrors: error with context

* httperrors: HTTPError

* treewide: fix typo

* treewide: use en in source code

* locales: initial version
This commit is contained in:
Yousong Zhou
2020-08-25 15:26:31 +08:00
committed by GitHub
parent ca2e8bece3
commit c2bca8ab39
140 changed files with 39193 additions and 624 deletions
+3
View File
@@ -37,3 +37,6 @@ GTAGS
pkg/generated
*.orig
# gotext extracted
out.gotext.json
+1
View File
@@ -120,6 +120,7 @@ require (
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8
golang.org/x/text v0.3.3
golang.org/x/tools v0.0.0-20200515220128-d3bf790afa53 // indirect
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543
golang.zx2c4.com/wireguard/wgctrl v0.0.0-20191008142428-8d021180e987
+2
View File
@@ -926,6 +926,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
+1
View File
@@ -0,0 +1 @@
package locales
+3252
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+23 -23
View File
@@ -188,7 +188,7 @@ func (h *AuthHandlers) GetRegionsResponse(ctx context.Context, w http.ResponseWr
func (h *AuthHandlers) getRegions(ctx context.Context, w http.ResponseWriter, req *http.Request) {
resp, err := h.GetRegionsResponse(ctx, w, req)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, resp)
@@ -197,7 +197,7 @@ func (h *AuthHandlers) getRegions(ctx context.Context, w http.ResponseWriter, re
func (h *AuthHandlers) getUser(ctx context.Context, w http.ResponseWriter, req *http.Request) {
data, err := getUserInfo(ctx, req)
if err != nil {
httperrors.NotFoundError(w, err.Error())
httperrors.NotFoundError(ctx, w, err.Error())
return
}
body := jsonutils.NewDict()
@@ -470,12 +470,12 @@ type PreLoginFunc func(ctx context.Context, req *http.Request, uname string, bod
func (h *AuthHandlers) postLoginHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
body, err := appsrv.FetchJSON(req)
if err != nil {
httperrors.InvalidInputError(w, "fetch json for request: %v", err)
httperrors.InvalidInputError(ctx, w, "fetch json for request: %v", err)
return
}
err = h.doLogin(ctx, w, req, body)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
// normal
@@ -928,7 +928,7 @@ func (h *AuthHandlers) getPermissionDetails(ctx context.Context, w http.Response
_, query, body := appsrv.FetchEnv(ctx, w, req)
if body == nil {
httperrors.InvalidInputError(w, "body is empty")
httperrors.InvalidInputError(ctx, w, "body is empty")
return
}
var name string
@@ -937,7 +937,7 @@ func (h *AuthHandlers) getPermissionDetails(ctx context.Context, w http.Response
}
result, err := policy.ExplainRpc(ctx, t, body, name)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -957,18 +957,18 @@ func (h *AuthHandlers) getResources(ctx context.Context, w http.ResponseWriter,
func (h *AuthHandlers) doCreatePolicies(ctx context.Context, w http.ResponseWriter, req *http.Request) {
t := AppContextToken(ctx)
// if !utils.IsInStringArray("admin", t.GetRoles()) || t.GetProjectName() != "system" {
// httperrors.ForbiddenError(w, "not allow to create policy")
// httperrors.ForbiddenError(ctx, w, "not allow to create policy")
// return
// }
_, _, body := appsrv.FetchEnv(ctx, w, req)
if body == nil {
httperrors.InvalidInputError(w, "body is empty")
httperrors.InvalidInputError(ctx, w, "body is empty")
return
}
s := auth.GetSession(ctx, t, FetchRegion(req), "")
result, err := policytool.PolicyCreate(s, body)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, result)
@@ -977,18 +977,18 @@ func (h *AuthHandlers) doCreatePolicies(ctx context.Context, w http.ResponseWrit
func (h *AuthHandlers) doPatchPolicy(ctx context.Context, w http.ResponseWriter, req *http.Request) {
t := AppContextToken(ctx)
// if !utils.IsInStringArray("admin", t.GetRoles()) || t.GetProjectName() != "system" {
// httperrors.ForbiddenError(w, "not allow to create policy")
// httperrors.ForbiddenError(ctx, w, "not allow to create policy")
// return
// }
params, _, body := appsrv.FetchEnv(ctx, w, req)
if body == nil {
httperrors.InvalidInputError(w, "request body is empty")
httperrors.InvalidInputError(ctx, w, "request body is empty")
return
}
s := auth.GetSession(ctx, t, FetchRegion(req), "")
result, err := policytool.PolicyPatch(s, params["<policy_id>"], body)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, result)
@@ -997,7 +997,7 @@ func (h *AuthHandlers) doPatchPolicy(ctx context.Context, w http.ResponseWriter,
func (h *AuthHandlers) doDeletePolicies(ctx context.Context, w http.ResponseWriter, req *http.Request) {
t := AppContextToken(ctx)
// if !utils.IsInStringArray("admin", t.GetRoles()) || t.GetProjectName() != "system" {
// httperrors.ForbiddenError(w, "not allow to create policy")
// httperrors.ForbiddenError(ctx, w, "not allow to create policy")
// return
// }
_, query, _ := appsrv.FetchEnv(ctx, w, req)
@@ -1005,7 +1005,7 @@ func (h *AuthHandlers) doDeletePolicies(ctx context.Context, w http.ResponseWrit
idlist, e := query.GetArray("id")
if e != nil || len(idlist) == 0 {
httperrors.InvalidInputError(w, "missing id")
httperrors.InvalidInputError(ctx, w, "missing id")
return
}
idStrList := jsonutils.JSONArray2StringArray(idlist)
@@ -1040,19 +1040,19 @@ func (h *AuthHandlers) doDeletePolicies(ctx context.Context, w http.ResponseWrit
func (h *AuthHandlers) resetUserPassword(ctx context.Context, w http.ResponseWriter, req *http.Request) {
t, authToken, err := fetchAuthInfo(ctx, req)
if err != nil {
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail: %s", err)
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail: %s", err)
return
}
_, _, body := appsrv.FetchEnv(ctx, w, req)
if body == nil {
httperrors.InvalidInputError(w, "body is empty")
httperrors.InvalidInputError(ctx, w, "body is empty")
return
}
user, err := fetchUserInfoFromToken(ctx, req, t)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -1062,13 +1062,13 @@ func (h *AuthHandlers) resetUserPassword(ctx context.Context, w http.ResponseWri
passcode, _ := body.GetString("passcode")
if newPwd != confirmPwd {
httperrors.InputParameterError(w, "new password mismatch")
httperrors.InputParameterError(ctx, w, "new password mismatch")
return
}
// 1.验证原密码正确,且idp_driver为空
if isIdpUser(user) {
httperrors.ForbiddenError(w, "not support reset user password")
httperrors.ForbiddenError(ctx, w, "not support reset user password")
return
}
@@ -1078,11 +1078,11 @@ func (h *AuthHandlers) resetUserPassword(ctx context.Context, w http.ResponseWri
switch httperr := err.(type) {
case *httputils.JSONClientError:
if httperr.Code == 409 {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
}
httperrors.InputParameterError(w, "密码错误")
httperrors.InputParameterError(ctx, w, "密码错误")
return
}
@@ -1091,7 +1091,7 @@ func (h *AuthHandlers) resetUserPassword(ctx context.Context, w http.ResponseWri
if isMfaEnabled(user) {
err = authToken.VerifyTotpPasscode(s, t.GetUserId(), passcode)
if err != nil {
httperrors.InputParameterError(w, "invalid passcode")
httperrors.InputParameterError(ctx, w, "invalid passcode")
return
}
}
@@ -1101,7 +1101,7 @@ func (h *AuthHandlers) resetUserPassword(ctx context.Context, w http.ResponseWri
params.Set("password", jsonutils.NewString(newPwd))
_, err = modules.UsersV3.Patch(s, t.GetUserId(), params)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
+18 -18
View File
@@ -205,7 +205,7 @@ func validateTotpRecoverySecrets(s *mcclient.ClientSession, uid string, question
func initTotpSecrets(ctx context.Context, w http.ResponseWriter, req *http.Request) {
t, authToken, err := fetchAuthInfo(ctx, req)
if err != nil {
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail %s", err)
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail %s", err)
return
}
if authToken.IsTotpInitialized() {
@@ -216,7 +216,7 @@ func initTotpSecrets(ctx context.Context, w http.ResponseWriter, req *http.Reque
s := auth.GetAdminSession(ctx, FetchRegion(req), "")
code, err := doCreateUserTotpCred(s, t)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -232,25 +232,25 @@ func initTotpSecrets(ctx context.Context, w http.ResponseWriter, req *http.Reque
func validatePasscodeHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
t, authToken, err := fetchAuthInfo(ctx, req)
if err != nil {
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail %s", err)
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail %s", err)
return
}
s := auth.GetAdminSession(ctx, FetchRegion(req), "")
_, _, body := appsrv.FetchEnv(ctx, w, req)
if body == nil {
httperrors.InvalidInputError(w, "body is empty")
httperrors.InvalidInputError(ctx, w, "body is empty")
return
}
passcode, err := body.GetString("passcode")
if err != nil {
httperrors.MissingParameterError(w, "passcode")
httperrors.MissingParameterError(ctx, w, "passcode")
return
}
if len(passcode) != 6 {
httperrors.InputParameterError(w, "passcode is a 6-digits string")
httperrors.InputParameterError(ctx, w, "passcode is a 6-digits string")
return
}
@@ -260,7 +260,7 @@ func validatePasscodeHandler(ctx context.Context, w http.ResponseWriter, req *ht
if err != nil {
log.Warningf("VerifyTotpPasscode %s", err.Error())
httperrors.InvalidCredentialError(w, "invalid passcode: %v", err)
httperrors.InvalidCredentialError(ctx, w, "invalid passcode: %v", err)
return
}
@@ -271,32 +271,32 @@ func validatePasscodeHandler(ctx context.Context, w http.ResponseWriter, req *ht
func resetTotpSecrets(ctx context.Context, w http.ResponseWriter, req *http.Request) {
t, _, err := fetchAuthInfo(ctx, req)
if err != nil {
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail %s", err)
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail %s", err)
return
}
s := auth.GetAdminSession(ctx, FetchRegion(req), "")
_, _, body := appsrv.FetchEnv(ctx, w, req)
if body == nil {
httperrors.InvalidInputError(w, "body is empty")
httperrors.InvalidInputError(ctx, w, "body is empty")
return
}
uid := t.GetUserId()
if len(uid) == 0 {
httperrors.ConflictError(w, "uid is empty")
httperrors.ConflictError(ctx, w, "uid is empty")
return
}
err = validateTotpRecoverySecrets(s, uid, body)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
code, err := resetUserTotpCred(s, t)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -309,7 +309,7 @@ func resetTotpSecrets(ctx context.Context, w http.ResponseWriter, req *http.Requ
func listTotpRecoveryQuestions(ctx context.Context, w http.ResponseWriter, req *http.Request) {
t, _, err := fetchAuthInfo(ctx, req)
if err != nil {
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail %s", err)
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail %s", err)
return
}
@@ -318,7 +318,7 @@ func listTotpRecoveryQuestions(ctx context.Context, w http.ResponseWriter, req *
ss, err := modules.Credentials.GetRecoverySecrets(s, t.GetUserId())
if len(ss) == 0 {
log.Errorf("ListTotpRecoveryQuestions %s", err.Error())
httperrors.NotFoundError(w, "no revocery questions.")
httperrors.NotFoundError(ctx, w, "no revocery questions.")
return
}
@@ -335,27 +335,27 @@ func listTotpRecoveryQuestions(ctx context.Context, w http.ResponseWriter, req *
func resetTotpRecoveryQuestions(ctx context.Context, w http.ResponseWriter, req *http.Request) {
t, _, err := fetchAuthInfo(ctx, req)
if err != nil {
httperrors.InvalidCredentialError(w, "fetchAuthInfo fail %s", err)
httperrors.InvalidCredentialError(ctx, w, "fetchAuthInfo fail %s", err)
return
}
s := auth.GetAdminSession(ctx, FetchRegion(req), "")
_, _, body := appsrv.FetchEnv(ctx, w, req)
if body == nil {
httperrors.InvalidInputError(w, "body is empty")
httperrors.InvalidInputError(ctx, w, "body is empty")
return
}
questions := make([]modules.SRecoverySecret, 0)
err = body.Unmarshal(&questions)
if err != nil {
httperrors.InvalidInputError(w, "unmarshal questions: %v", err)
httperrors.InvalidInputError(ctx, w, "unmarshal questions: %v", err)
return
}
err = setTotpRecoverySecrets(s, t.GetUserId(), questions)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
+8 -8
View File
@@ -47,18 +47,18 @@ func (h *CSRFResourceHandler) Bind(app *appsrv.Application) {
func getAdminSession(ctx context.Context, apiVer string, region string, w http.ResponseWriter) *mcclient.ClientSession {
adminToken := auth.AdminCredential()
if adminToken == nil {
httperrors.NotFoundError(w, "get admin credential is nil")
httperrors.NotFoundError(ctx, w, "get admin credential is nil")
return nil
}
regions := adminToken.GetRegions()
log.Infof("CSRF regions: %v", regions)
if len(regions) == 0 {
httperrors.NotFoundError(w, "no usable regions, please contact admin")
httperrors.NotFoundError(ctx, w, "no usable regions, please contact admin")
return nil
}
ret, _ := sets.InArray(region, regions)
if !ret {
httperrors.NotFoundError(w, "illegal region %s, please contact admin", region)
httperrors.NotFoundError(ctx, w, "illegal region %s, please contact admin", region)
}
s := auth.GetAdminSession(ctx, region, apiVer)
return s
@@ -71,7 +71,7 @@ func fetchEnv3Csrf(ctx context.Context, w http.ResponseWriter, r *http.Request)
}
module3, e := modulebase.GetModule(session, params[ResName3])
if e != nil || module == nil {
httperrors.NotFoundError(w, fmt.Sprintf("resource %s not found", params[ResName3]))
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s not found", params[ResName3]))
return nil, nil, nil, nil, nil, nil, nil
}
return module, module2, module3, session, params, query, body
@@ -84,7 +84,7 @@ func fetchEnv2Csrf(ctx context.Context, w http.ResponseWriter, r *http.Request)
}
module2, e := modulebase.GetModule(session, params[ResName2])
if e != nil || module == nil {
httperrors.NotFoundError(w, fmt.Sprintf("resource %s not found", params[ResName2]))
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s not found", params[ResName2]))
return nil, nil, nil, nil, nil, nil
}
return module, module2, session, params, query, body
@@ -94,7 +94,7 @@ func fetchEnvCsrf(ctx context.Context, w http.ResponseWriter, r *http.Request) (
session, params, query, body := fetchEnvCsrf0(ctx, w, r)
module, e := modulebase.GetModule(session, params[ResName])
if e != nil || module == nil {
httperrors.NotFoundError(w, fmt.Sprintf("resource %s not found", params[ResName]))
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s not found", params[ResName]))
return nil, nil, nil, nil, nil
}
return module, session, params, query, body
@@ -105,7 +105,7 @@ func fetchEnvCsrf0(ctx context.Context, w http.ResponseWriter, r *http.Request)
region := r.URL.Query().Get("region")
log.Println("csrf region from url:", region)
if len(region) < 1 {
httperrors.NotFoundError(w, fmt.Sprintf("region %s is empty", region))
httperrors.NotFoundError(ctx, w, fmt.Sprintf("region %s is empty", region))
return nil, nil, nil, nil
}
log.Infof("csrf region from url: %s", region)
@@ -135,7 +135,7 @@ func getHandlerCsrf(ctx context.Context, w http.ResponseWriter, r *http.Request)
}
obj, e := module.Get(session, params[ResID], query)
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
+12 -12
View File
@@ -78,7 +78,7 @@ func (h *AuthHandlers) getIdpSsoRedirectUri(ctx context.Context, w http.Response
if query != nil && query.Contains("linkuser") {
t, authToken, _ := fetchAuthInfo(ctx, req)
if t == nil {
httperrors.InvalidCredentialError(w, "invalid credential")
httperrors.InvalidCredentialError(ctx, w, "invalid credential")
return
}
linkuser = t.GetUserId()
@@ -101,7 +101,7 @@ func (h *AuthHandlers) getIdpSsoRedirectUri(ctx context.Context, w http.Response
}
resp, err := modules.IdentityProviders.GetSpecific(s, idpId, "sso-redirect-uri", jsonutils.Marshal(input))
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
redirUrl, _ := resp.GetString("uri")
@@ -151,7 +151,7 @@ func (h *AuthHandlers) handleSsoLogin(ctx context.Context, w http.ResponseWriter
missing = append(missing, "idp_referer")
}
if len(missing) > 0 {
httperrors.TimeoutError(w, "session expires, missing %s", strings.Join(missing, ","))
httperrors.TimeoutError(ctx, w, "session expires, missing %s", strings.Join(missing, ","))
return
}
@@ -165,21 +165,21 @@ func (h *AuthHandlers) handleSsoLogin(ctx context.Context, w http.ResponseWriter
case "GET":
body, err = jsonutils.ParseQueryString(req.URL.RawQuery)
if err != nil {
httperrors.InputParameterError(w, "parse query string error: %s", err)
httperrors.InputParameterError(ctx, w, "parse query string error: %s", err)
return
}
case "POST":
formData, err := appsrv.Fetch(req)
if err != nil {
httperrors.InputParameterError(w, "fetch formdata error: %s", err)
httperrors.InputParameterError(ctx, w, "fetch formdata error: %s", err)
}
body, err = jsonutils.ParseQueryString(string(formData))
if err != nil {
httperrors.InputParameterError(w, "parse form data error: %s", err)
httperrors.InputParameterError(ctx, w, "parse form data error: %s", err)
return
}
default:
httperrors.InputParameterError(w, "invalid request")
httperrors.InputParameterError(ctx, w, "invalid request")
return
}
@@ -357,7 +357,7 @@ func handleUnlinkIdp(ctx context.Context, w http.ResponseWriter, req *http.Reque
body, err := appsrv.FetchJSON(req)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -365,7 +365,7 @@ func handleUnlinkIdp(ctx context.Context, w http.ResponseWriter, req *http.Reque
idpEntityId, _ := body.GetString("idp_entity_id")
if len(idpId) == 0 || len(idpEntityId) == 0 {
httperrors.InputParameterError(w, "empty idp_id or idp_entity_id")
httperrors.InputParameterError(ctx, w, "empty idp_id or idp_entity_id")
return
}
@@ -376,7 +376,7 @@ func handleUnlinkIdp(ctx context.Context, w http.ResponseWriter, req *http.Reque
}
_, err = modules.UsersV3.PerformAction(s, t.GetUserId(), "unlink-idp", jsonutils.Marshal(input))
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.Send(w, "")
@@ -388,7 +388,7 @@ func fetchIdpBasicConfig(ctx context.Context, w http.ResponseWriter, req *http.R
idpId := params["<idp_id>"]
info, err := getIdpBasicConfig(s, idpId)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, info)
@@ -426,7 +426,7 @@ func fetchIdpSAMLMetadata(ctx context.Context, w http.ResponseWriter, req *http.
query.Set("redirect_uri", jsonutils.NewString(getSsoCallbackUrl()))
md, err := modules.IdentityProviders.GetSpecific(s, idpId, "saml-metadata", query)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, md)
+9 -6
View File
@@ -65,15 +65,18 @@ func readImageForm(r *multipart.Reader) (map[string]string, *multipart.Part, err
}
func imageUploadHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
const (
invalidForm = "invalid form"
)
reader, e := r.MultipartReader()
if e != nil {
httperrors.InvalidInputError(w, "无效的表单")
httperrors.InvalidInputError(ctx, w, invalidForm)
return
}
p, f, e := readImageForm(reader)
if e != nil {
httperrors.InvalidInputError(w, "无效的表单")
httperrors.InvalidInputError(ctx, w, invalidForm)
return
}
@@ -81,19 +84,19 @@ func imageUploadHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
name, ok := p["name"]
if !ok {
httperrors.InvalidInputError(w, "缺少镜像名称")
httperrors.InvalidInputError(ctx, w, "missing image name")
return
}
params.Add(jsonutils.NewString(name), "name")
_imageSize, ok := p["image_size"]
if !ok {
httperrors.InvalidInputError(w, "缺少文件信息")
httperrors.InvalidInputError(ctx, w, "missing image size")
return
}
imageSize, e := strconv.ParseInt(_imageSize, 10, 64)
if e != nil {
httperrors.InvalidInputError(w, "文件信息错误")
httperrors.InvalidInputError(ctx, w, "invalid image size")
return
}
@@ -110,7 +113,7 @@ func imageUploadHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
res, e := modules.Images.Upload(s, params, f, imageSize)
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
return
} else {
appsrv.SendJSON(w, res)
+9 -9
View File
@@ -89,12 +89,12 @@ func (h *K8sResourceHandler) fetchEnv(ctx context.Context, req *http.Request) (*
func (h *K8sResourceHandler) Get(ctx context.Context, w http.ResponseWriter, req *http.Request) {
env, err := h.fetchEnv(ctx, req)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
detail, err := k8s.RawResource.Get(env.session, env.kind, env.namespace, env.name, env.cluster)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, detail)
@@ -103,12 +103,12 @@ func (h *K8sResourceHandler) Get(ctx context.Context, w http.ResponseWriter, req
func (h *K8sResourceHandler) GetYAML(ctx context.Context, w http.ResponseWriter, req *http.Request) {
env, err := h.fetchEnv(ctx, req)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
detail, err := k8s.RawResource.GetYAML(env.session, env.kind, env.namespace, env.name, env.cluster)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.Send(w, string(detail))
@@ -117,17 +117,17 @@ func (h *K8sResourceHandler) GetYAML(ctx context.Context, w http.ResponseWriter,
func (h *K8sResourceHandler) Put(ctx context.Context, w http.ResponseWriter, req *http.Request) {
env, err := h.fetchEnv(ctx, req)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
data, err := appsrv.FetchJSON(req)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
err = k8s.RawResource.Put(env.session, env.kind, env.namespace, env.name, data, env.cluster)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
w.WriteHeader(http.StatusCreated)
@@ -136,11 +136,11 @@ func (h *K8sResourceHandler) Put(ctx context.Context, w http.ResponseWriter, req
func (h *K8sResourceHandler) Delete(ctx context.Context, w http.ResponseWriter, req *http.Request) {
env, err := h.fetchEnv(ctx, req)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
if err := k8s.RawResource.Delete(env.session, env.kind, env.namespace, env.name, env.cluster); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
w.WriteHeader(http.StatusOK)
+1 -1
View File
@@ -129,7 +129,7 @@ func FetchAuthToken(f func(context.Context, http.ResponseWriter, *http.Request))
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
ctx, err := fetchAndSetAuthContext(ctx, w, r)
if err != nil {
httperrors.InvalidCredentialError(w, "No token in header: %v", err)
httperrors.InvalidCredentialError(ctx, w, "No token in header: %v", err)
return
}
f(ctx, w, r)
+41 -41
View File
@@ -112,7 +112,7 @@ func (mh *MiscHandler) PostUploads(ctx context.Context, w http.ResponseWriter, r
var maxMemory int64 = 10 << 20
e := req.ParseMultipartForm(maxMemory)
if e != nil {
httperrors.InvalidInputError(w, "invalid form")
httperrors.InvalidInputError(ctx, w, "invalid form")
return
}
@@ -121,7 +121,7 @@ func (mh *MiscHandler) PostUploads(ctx context.Context, w http.ResponseWriter, r
actions, ok := params["action"]
if !ok || len(actions) == 0 || len(actions[0]) == 0 {
err := httperrors.NewInputParameterError("Missing parameter %s", "action")
httperrors.JsonClientError(w, err)
httperrors.JsonClientError(ctx, w, err)
return
}
@@ -136,7 +136,7 @@ func (mh *MiscHandler) PostUploads(ctx context.Context, w http.ResponseWriter, r
return
default:
err := httperrors.NewInputParameterError("Unsupported action %s", actions[0])
httperrors.JsonClientError(w, err)
httperrors.JsonClientError(ctx, w, err)
return
}
}
@@ -147,7 +147,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
hostfiles, ok := files["hosts"]
if !ok || len(hostfiles) == 0 || hostfiles[0] == nil {
e := httperrors.NewInputParameterError("Missing parameter %s", "hosts")
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -155,7 +155,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
contentType := fileHeader.Get("Content-Type")
if contentType != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" {
e := httperrors.NewInputParameterError("Wrong content type %s, required application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", contentType)
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -164,7 +164,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
if err != nil {
log.Errorf(err.Error())
e := httperrors.NewInternalServerError("can't open file")
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -172,14 +172,14 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
if err != nil {
log.Errorf(err.Error())
e := httperrors.NewInternalServerError("can't parse file")
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
rows := xlsx.GetRows("hosts")
if len(rows) == 0 {
e := httperrors.NewGeneralError(fmt.Errorf("empty file content"))
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -198,7 +198,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
}
if !titlesOk {
httperrors.InputParameterError(w, "template file is invalid.please check.")
httperrors.InputParameterError(ctx, w, "template file is invalid.please check.")
return
}
@@ -223,7 +223,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
paramKeys = append(paramKeys, "access_ip")
default:
e := httperrors.NewInternalServerError("empty file content")
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
}
@@ -231,7 +231,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
// skipped header row
if len(rows) > BATCH_HOST_REGISTER_QUANTITY_LIMITATION {
e := httperrors.NewInputParameterError(fmt.Sprintf("beyond limitation. excel file rows must less than %d", BATCH_HOST_REGISTER_QUANTITY_LIMITATION))
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -258,7 +258,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
}
if e != nil {
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -279,7 +279,7 @@ func (mh *MiscHandler) DoBatchHostRegister(ctx context.Context, w http.ResponseW
submitResult, err := modules.Hosts.BatchRegister(s, paramKeys, params)
if err != nil {
e := httperrors.NewGeneralError(err)
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -295,7 +295,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
userfiles, ok := files["users"]
if !ok || len(userfiles) == 0 || userfiles[0] == nil {
e := httperrors.NewInputParameterError("Missing parameter %s", "users")
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -303,7 +303,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
contentType := fileHeader.Get("Content-Type")
if contentType != "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" {
e := httperrors.NewInputParameterError("Wrong content type %s, required application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", contentType)
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -312,7 +312,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
if err != nil {
log.Errorf(err.Error())
e := httperrors.NewInternalServerError("can't open file")
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -320,7 +320,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
if err != nil {
log.Errorf(err.Error())
e := httperrors.NewInternalServerError("can't parse file")
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -328,11 +328,11 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
rows := xlsx.GetRows("users")
if len(rows) <= 1 {
e := httperrors.NewInputParameterError("empty file")
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
} else if len(rows) > BATCH_USER_REGISTER_QUANTITY_LIMITATION {
e := httperrors.NewInputParameterError(fmt.Sprintf("beyond limitation.excel file rows must less than %d", BATCH_USER_REGISTER_QUANTITY_LIMITATION))
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -354,7 +354,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
if len(name) == 0 {
e := httperrors.NewClientError("row %d name is empty", rowIdx)
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
@@ -362,13 +362,13 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
if !ok {
if len(domain) == 0 {
e := httperrors.NewClientError("row %d domain is empty", rowIdx)
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
id, err := modules.Domains.GetId(adminS, domain, nil)
if err != nil {
httperrors.JsonClientError(w, httperrors.NewGeneralError(err))
httperrors.JsonClientError(ctx, w, httperrors.NewGeneralError(err))
return
}
@@ -378,7 +378,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
if _, ok := names[name+"/"+domainId]; ok {
e := httperrors.NewClientError("row %d duplicate name %s", rowIdx, name)
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
} else {
names[name+"/"+domainId] = true
@@ -417,7 +417,7 @@ func (mh *MiscHandler) DoBatchUserRegister(ctx context.Context, w http.ResponseW
if err := userG.Wait(); err != nil {
e := httperrors.NewGeneralError(err)
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
return
}
@@ -428,7 +428,7 @@ func (mh *MiscHandler) getDownloadsHandler(ctx context.Context, w http.ResponseW
params := appctx.AppContextParams(ctx)
template, ok := params["<template_id>"]
if !ok || len(template) == 0 {
httperrors.InvalidInputError(w, "not found")
httperrors.InvalidInputError(ctx, w, "not found")
return
}
@@ -439,28 +439,28 @@ func (mh *MiscHandler) getDownloadsHandler(ctx context.Context, w http.ResponseW
records := [][]string{BatchHostRegisterTemplate}
content, err = writeXlsx("hosts", records)
if err != nil {
httperrors.InternalServerError(w, "internal server error")
httperrors.InternalServerError(ctx, w, "internal server error")
return
}
case "BatchHostISORegister":
records := [][]string{BatchHostISORegisterTemplate}
content, err = writeXlsx("hosts", records)
if err != nil {
httperrors.InternalServerError(w, "internal server error")
httperrors.InternalServerError(ctx, w, "internal server error")
return
}
case "BatchHostPXERegister":
records := [][]string{BatchHostPXERegisterTemplate}
content, err = writeXlsx("hosts", records)
if err != nil {
httperrors.InternalServerError(w, "internal server error")
httperrors.InternalServerError(ctx, w, "internal server error")
return
}
case "BatchUserRegister":
records := [][]string{{"*用户名(user", "用户密码(password", "*部门/域(domain", "*是否登录控制台(allow_web_consoletrue、false"}}
content, err = writeXlsx("users", records)
if err != nil {
httperrors.InternalServerError(w, "internal server error")
httperrors.InternalServerError(ctx, w, "internal server error")
return
}
case "BatchProjectRegister":
@@ -474,11 +474,11 @@ func (mh *MiscHandler) getDownloadsHandler(ctx context.Context, w http.ResponseW
records := [][]string{titles}
content, err = writeXlsx("projects", records)
if err != nil {
httperrors.InternalServerError(w, "internal server error")
httperrors.InternalServerError(ctx, w, "internal server error")
return
}
default:
httperrors.InputParameterError(w, "template not found %s", template)
httperrors.InputParameterError(ctx, w, "template not found %s", template)
return
}
@@ -492,12 +492,12 @@ func (mh *MiscHandler) postPIUploads(ctx context.Context, w http.ResponseWriter,
// 5 MB
var maxMemory int64 = 5 << 20
if req.ContentLength > maxMemory {
httperrors.InvalidInputError(w, "request body is too large.")
httperrors.InvalidInputError(ctx, w, "request body is too large.")
return
}
if !strings.Contains(req.Header.Get("Content-Type"), "multipart/form-data") {
httperrors.InvalidInputError(w, "invalid multipart form")
httperrors.InvalidInputError(ctx, w, "invalid multipart form")
return
}
@@ -507,7 +507,7 @@ func (mh *MiscHandler) postPIUploads(ctx context.Context, w http.ResponseWriter,
header.Set("Content-Length", req.Header.Get("Content-Length"))
resp, err := modules.ProcessInstance.Upload(s, header, req.Body)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -518,38 +518,38 @@ func (mh *MiscHandler) postS3UploadHandler(ctx context.Context, w http.ResponseW
reader, e := r.MultipartReader()
if e != nil {
log.Debugf("postS3UploadHandler.MultipartReader %s", e)
httperrors.InvalidInputError(w, "invalid form")
httperrors.InvalidInputError(ctx, w, "invalid form")
return
}
p, f, e := readImageForm(reader)
if e != nil {
log.Debugf("postS3UploadHandler.readImageForm %s", e)
httperrors.InvalidInputError(w, "invalid form")
httperrors.InvalidInputError(ctx, w, "invalid form")
return
}
bucket_id, ok := p["bucket_id"]
if !ok {
httperrors.MissingParameterError(w, "bucket_id")
httperrors.MissingParameterError(ctx, w, "bucket_id")
return
}
key, ok := p["key"]
if !ok {
httperrors.MissingParameterError(w, "key")
httperrors.MissingParameterError(ctx, w, "key")
return
}
_content_length, ok := p["content_length"]
if !ok {
httperrors.MissingParameterError(w, "content_length")
httperrors.MissingParameterError(ctx, w, "content_length")
return
}
content_length, e := strconv.ParseInt(_content_length, 10, 64)
if e != nil {
httperrors.InvalidInputError(w, "invalid content_length %s", _content_length)
httperrors.InvalidInputError(ctx, w, "invalid content_length %s", _content_length)
return
}
@@ -563,7 +563,7 @@ func (mh *MiscHandler) postS3UploadHandler(ctx context.Context, w http.ResponseW
meta.Set("Content-Type", "application/octet-stream")
e = modules.Buckets.Upload(s, bucket_id, key, f, content_length, storage_class, acl, meta)
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
return
}
appsrv.SendJSON(w, jsonutils.NewDict())
+3 -3
View File
@@ -145,7 +145,7 @@ func doOIDCAuth(ctx context.Context, req *http.Request, query jsonutils.JSONObje
func handleOIDCToken(ctx context.Context, w http.ResponseWriter, req *http.Request) {
resp, err := validateOIDCToken(ctx, req)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, jsonutils.Marshal(resp))
@@ -327,7 +327,7 @@ func handleOIDCConfiguration(ctx context.Context, w http.ResponseWriter, req *ht
func handleOIDCJWKeys(ctx context.Context, w http.ResponseWriter, req *http.Request) {
keyJson, err := clientman.GetJWKs(ctx)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, keyJson)
@@ -336,7 +336,7 @@ func handleOIDCJWKeys(ctx context.Context, w http.ResponseWriter, req *http.Requ
func handleOIDCUserInfo(ctx context.Context, w http.ResponseWriter, req *http.Request) {
data, err := getUserInfo(ctx, req)
if err != nil {
httperrors.NotFoundError(w, err.Error())
httperrors.NotFoundError(ctx, w, "%v", err)
return
}
appsrv.SendJSON(w, data)
+65 -65
View File
@@ -137,7 +137,7 @@ func (f *ResourceHandlers) AddDelete(mf appsrv.MiddlewareFunc) *ResourceHandlers
return f
}
func fetchIdList(query jsonutils.JSONObject, w http.ResponseWriter) []string {
func fetchIdList(ctx context.Context, query jsonutils.JSONObject, w http.ResponseWriter) []string {
idlist, e := query.GetArray("id")
if e == nil && len(idlist) > 0 {
queryDict := query.(*jsonutils.JSONDict)
@@ -146,7 +146,7 @@ func fetchIdList(query jsonutils.JSONObject, w http.ResponseWriter) []string {
return jsonutils.JSONArray2StringArray(idlist)
} else {
log.Debugf("Cannot find idlist in query: %s", query)
httperrors.InvalidInputError(w, "No idlist found")
httperrors.InvalidInputError(ctx, w, "No idlist found")
return nil
}
}
@@ -157,20 +157,20 @@ func fetchIdList(query jsonutils.JSONObject, w http.ResponseWriter) []string {
func (f *ResourceHandlers) listHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r)
if req.Error() != nil {
httperrors.GeneralServerError(w, req.Error())
httperrors.GeneralServerError(ctx, w, req.Error())
return
}
jmod, _ := modulebase.GetJointModule(req.Session(), req.ResName())
if jmod != nil {
f.doList(req.Session(), jmod, req.Query(), w, r)
f.doList(ctx, req.Session(), jmod, req.Query(), w, r)
} else {
if err := req.WithMod1().Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
batchGet, err := req.Query().Bool("batchGet")
if err == nil && batchGet {
idlist := fetchIdList(req.Query(), w)
idlist := fetchIdList(ctx, req.Query(), w)
if idlist == nil {
return
}
@@ -182,12 +182,12 @@ func (f *ResourceHandlers) listHandler(ctx context.Context, w http.ResponseWrite
ret := req.Mod1().BatchGet(req.Session(), idlist, req.Query())
appsrv.SendJSON(w, modulebase.ListResult2JSON(modulebase.SubmitResults2ListResult(ret)))
} else {
f.doList(req.Session(), req.Mod1(), req.Query(), w, r)
f.doList(ctx, req.Session(), req.Mod1(), req.Query(), w, r)
}
}
}
func (f *ResourceHandlers) doList(session *mcclient.ClientSession, module modulebase.IBaseManager, query jsonutils.JSONObject, w http.ResponseWriter, r *http.Request) {
func (f *ResourceHandlers) doList(ctx context.Context, session *mcclient.ClientSession, module modulebase.IBaseManager, query jsonutils.JSONObject, w http.ResponseWriter, r *http.Request) {
var exportKeys []string
var exportTexts []string
exportFormat, _ := query.GetString("export")
@@ -201,13 +201,13 @@ func (f *ResourceHandlers) doList(session *mcclient.ClientSession, module module
exportTexts = strings.Split(exportTextStr, ",")
}
if len(exportKeys) == 0 {
httperrors.InvalidInputError(w, "missing export keys")
httperrors.InvalidInputError(ctx, w, "missing export keys")
return
} else if len(exportKeys) != len(exportTexts) {
if len(exportTexts) == 0 {
exportTexts = exportKeys
} else {
httperrors.InvalidInputError(w, "inconsistent export keys and texts")
httperrors.InvalidInputError(ctx, w, "inconsistent export keys and texts")
return
}
}
@@ -219,7 +219,7 @@ func (f *ResourceHandlers) doList(session *mcclient.ClientSession, module module
ret, e := module.List(session, query)
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else if len(exportFormat) > 0 {
w.Header().Set("Content-Description", "File Transfer")
w.Header().Set("Content-Transfer-Encoding", "binary")
@@ -236,12 +236,12 @@ func (f *ResourceHandlers) doList(session *mcclient.ClientSession, module module
func (f *ResourceHandlers) getHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
obj, e := req.Mod1().Get(req.Session(), req.ResID(), req.Query())
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -255,7 +255,7 @@ func (f *ResourceHandlers) getHandler(ctx context.Context, w http.ResponseWriter
func (f *ResourceHandlers) getSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
session := req.Session()
@@ -272,14 +272,14 @@ func (f *ResourceHandlers) getSpecHandler(ctx context.Context, w http.ResponseWr
ret, e = module2.ListInContext(session, query, module, req.ResID())
}
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, modulebase.ListResult2JSON(ret))
}
} else {
obj, e := module.GetSpecific(session, req.ResID(), req.Spec(), query)
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -291,7 +291,7 @@ func (f *ResourceHandlers) getSpecHandler(ctx context.Context, w http.ResponseWr
func (f *ResourceHandlers) getJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1().WithMod2()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -301,12 +301,12 @@ func (f *ResourceHandlers) getJointHandler(ctx context.Context, w http.ResponseW
jmod, e := modulebase.GetJointModule2(session, module, module2)
if e != nil {
httperrors.NotFoundError(w, fmt.Sprintf("resource %s-%s not exist", req.ResName(), req.ResName2()))
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s-%s not exist", req.ResName(), req.ResName2()))
return
}
obj, e := jmod.Get(session, req.ResID(), req.ResID2(), req.Query())
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -317,7 +317,7 @@ func (f *ResourceHandlers) getJointHandler(ctx context.Context, w http.ResponseW
func (f *ResourceHandlers) listInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
module := req.Mod1()
@@ -330,7 +330,7 @@ func (f *ResourceHandlers) listInContextsHandler(ctx context.Context, w http.Res
{InstanceManager: module2, InstanceId: req.ResID2()},
})
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, modulebase.ListResult2JSON(obj))
}
@@ -342,7 +342,7 @@ func (f *ResourceHandlers) listInContextsHandler(ctx context.Context, w http.Res
func (f *ResourceHandlers) createHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
module := req.Mod1()
@@ -353,7 +353,7 @@ func (f *ResourceHandlers) createHandler(ctx context.Context, w http.ResponseWri
if e == nil && count > 1 {
bodyDict, ok := body.(*jsonutils.JSONDict)
if !ok {
httperrors.GeneralServerError(w, fmt.Errorf("Fail to decode body"))
httperrors.GeneralServerError(ctx, w, fmt.Errorf("Fail to decode body"))
} else {
nbody := bodyDict.Copy("__count__")
ret := module.BatchCreate(session, nbody, int(count))
@@ -363,7 +363,7 @@ func (f *ResourceHandlers) createHandler(ctx context.Context, w http.ResponseWri
} else {
obj, e := module.Create(session, body)
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -375,7 +375,7 @@ func (f *ResourceHandlers) createHandler(ctx context.Context, w http.ResponseWri
func (f *ResourceHandlers) batchPerformActionHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
module := req.Mod1()
@@ -385,7 +385,7 @@ func (f *ResourceHandlers) batchPerformActionHandler(ctx context.Context, w http
if idlist, e := query.GetArray("id"); e != nil || len(idlist) == 0 {
if obj, e := module.PerformClassAction(session, req.Action(), body); e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -403,7 +403,7 @@ func (f *ResourceHandlers) batchPerformActionHandler(ctx context.Context, w http
func (f *ResourceHandlers) performActionHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
module := req.Mod1()
@@ -415,14 +415,14 @@ func (f *ResourceHandlers) performActionHandler(ctx context.Context, w http.Resp
var idlist []string
if module2, e := modulebase.GetModule(session, req.Action()); e == nil {
if jmod, e := modulebase.GetJointModule2(session, module, module2); e == nil {
if idlist = fetchIdList(query, w); idlist == nil {
if idlist = fetchIdList(ctx, query, w); idlist == nil {
return
}
ret := jmod.BatchAttach(session, req.ResID(), idlist, body)
w.WriteHeader(207)
appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
} else if jmod, e := modulebase.GetJointModule2(session, module2, module); e == nil {
if idlist = fetchIdList(query, w); idlist == nil {
if idlist = fetchIdList(ctx, query, w); idlist == nil {
return
}
ret := jmod.BatchAttach2(session, req.ResID(), idlist, body)
@@ -430,14 +430,14 @@ func (f *ResourceHandlers) performActionHandler(ctx context.Context, w http.Resp
appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
} else {
if obj, e = module2.CreateInContext(session, body, module, req.ResID()); e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
}
} else {
if obj, e = module.PerformAction(session, req.ResID(), req.Action(), body); e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -449,7 +449,7 @@ func (f *ResourceHandlers) performActionHandler(ctx context.Context, w http.Resp
func (f *ResourceHandlers) attachHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1().WithMod2()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
module := req.Mod1()
@@ -459,12 +459,12 @@ func (f *ResourceHandlers) attachHandler(ctx context.Context, w http.ResponseWri
jmod, e := modulebase.GetJointModule2(session, module, module2)
if e != nil {
httperrors.NotFoundError(w, fmt.Sprintf("resource %s-%s not exists", req.ResName(), req.ResName2()))
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s-%s not exists", req.ResName(), req.ResName2()))
return
}
obj, e := jmod.Attach(session, req.ResID(), req.ResID2(), body)
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -475,7 +475,7 @@ func (f *ResourceHandlers) attachHandler(ctx context.Context, w http.ResponseWri
func (f *ResourceHandlers) batchUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -483,7 +483,7 @@ func (f *ResourceHandlers) batchUpdateHandler(ctx context.Context, w http.Respon
query := req.Query()
body := req.Body()
idlist := fetchIdList(query, w)
idlist := fetchIdList(ctx, query, w)
if idlist == nil {
return
}
@@ -498,7 +498,7 @@ func (f *ResourceHandlers) batchUpdateHandler(ctx context.Context, w http.Respon
func (f *ResourceHandlers) batchPatchHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -506,7 +506,7 @@ func (f *ResourceHandlers) batchPatchHandler(ctx context.Context, w http.Respons
query := req.Query()
body := req.Body()
idlist := fetchIdList(query, w)
idlist := fetchIdList(ctx, query, w)
if idlist == nil {
return
}
@@ -521,7 +521,7 @@ func (f *ResourceHandlers) batchPatchHandler(ctx context.Context, w http.Respons
func (f *ResourceHandlers) updateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -530,7 +530,7 @@ func (f *ResourceHandlers) updateHandler(ctx context.Context, w http.ResponseWri
obj, e := module.Update(req.Session(), req.ResID(), body)
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -541,7 +541,7 @@ func (f *ResourceHandlers) updateHandler(ctx context.Context, w http.ResponseWri
func (f *ResourceHandlers) patchHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -550,7 +550,7 @@ func (f *ResourceHandlers) patchHandler(ctx context.Context, w http.ResponseWrit
obj, e := module.Patch(req.Session(), req.ResID(), body)
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -562,7 +562,7 @@ func (f *ResourceHandlers) patchHandler(ctx context.Context, w http.ResponseWrit
func (f *ResourceHandlers) updateJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1().WithMod2()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
session := req.Session()
@@ -578,7 +578,7 @@ func (f *ResourceHandlers) updateJointHandler(ctx context.Context, w http.Respon
obj, e = module2.PutInContext(session, req.ResID2(), body, module, req.ResID())
}
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -587,7 +587,7 @@ func (f *ResourceHandlers) updateJointHandler(ctx context.Context, w http.Respon
func (f *ResourceHandlers) patchJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1().WithMod2()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
session := req.Session()
@@ -603,7 +603,7 @@ func (f *ResourceHandlers) patchJointHandler(ctx context.Context, w http.Respons
obj, e = module2.PatchInContext(session, req.ResID2(), body, module, req.ResID())
}
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -616,7 +616,7 @@ func (f *ResourceHandlers) patchJointHandler(ctx context.Context, w http.Respons
func (f *ResourceHandlers) batchUpdateJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
session := req.Session()
@@ -629,7 +629,7 @@ func (f *ResourceHandlers) batchUpdateJointHandler(ctx context.Context, w http.R
spec := req.ResName2()
obj, e := module.PutSpecific(session, req.ResID(), spec, query, body)
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -638,16 +638,16 @@ func (f *ResourceHandlers) batchUpdateJointHandler(ctx context.Context, w http.R
req = req.WithMod2()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
module2 := req.Mod2()
jmod, e := modulebase.GetJointModule2(session, module, module2)
if e != nil { // update joint
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
return
}
idlist := fetchIdList(query, w)
idlist := fetchIdList(ctx, query, w)
ret := jmod.BatchUpdate(session, req.ResID(), idlist, query, body)
w.WriteHeader(207)
appsrv.SendJSON(w, modulebase.SubmitResults2JSON(ret))
@@ -658,7 +658,7 @@ func (f *ResourceHandlers) batchUpdateJointHandler(ctx context.Context, w http.R
func (f *ResourceHandlers) updateInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -667,7 +667,7 @@ func (f *ResourceHandlers) updateInContextsHandler(ctx context.Context, w http.R
{InstanceManager: req.Mod2(), InstanceId: req.ResID2()},
})
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -676,7 +676,7 @@ func (f *ResourceHandlers) updateInContextsHandler(ctx context.Context, w http.R
func (f *ResourceHandlers) patchInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
module := req.Mod1()
@@ -690,7 +690,7 @@ func (f *ResourceHandlers) patchInContextsHandler(ctx context.Context, w http.Re
{InstanceManager: module2, InstanceId: req.ResID2()},
})
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -701,11 +701,11 @@ func (f *ResourceHandlers) patchInContextsHandler(ctx context.Context, w http.Re
func (f *ResourceHandlers) batchDeleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
idlist := fetchIdList(req.Query(), w)
idlist := fetchIdList(ctx, req.Query(), w)
if idlist == nil {
return
}
@@ -719,12 +719,12 @@ func (f *ResourceHandlers) batchDeleteHandler(ctx context.Context, w http.Respon
func (f *ResourceHandlers) deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
obj, e := req.Mod1().DeleteWithParam(req.Session(), req.ResID(), req.Query(), req.Body())
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -735,10 +735,10 @@ func (f *ResourceHandlers) deleteHandler(ctx context.Context, w http.ResponseWri
func (f *ResourceHandlers) batchDetachHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1().WithMod2()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
idlist := fetchIdList(req.Query(), w)
idlist := fetchIdList(ctx, req.Query(), w)
if idlist == nil {
return
}
@@ -767,7 +767,7 @@ func (f *ResourceHandlers) batchDetachHandler(ctx context.Context, w http.Respon
func (f *ResourceHandlers) detachHandle(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1().WithMod2()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
session := req.Session()
@@ -782,7 +782,7 @@ func (f *ResourceHandlers) detachHandle(ctx context.Context, w http.ResponseWrit
obj, e = module2.DeleteInContextWithParam(session, req.ResID2(), req.Query(), req.Body(), module, req.ResID())
}
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
@@ -793,7 +793,7 @@ func (f *ResourceHandlers) detachHandle(ctx context.Context, w http.ResponseWrit
func (f *ResourceHandlers) deleteInContextsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
req := newRequest(ctx, w, r).WithMod1().WithMod2().WithMod3()
if err := req.Error(); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
session := req.Session()
@@ -808,7 +808,7 @@ func (f *ResourceHandlers) deleteInContextsHandler(ctx context.Context, w http.R
{InstanceManager: module2, InstanceId: req.ResID2()},
})
if e != nil {
httperrors.GeneralServerError(w, e)
httperrors.GeneralServerError(ctx, w, e)
} else {
appsrv.SendJSON(w, obj)
}
+6 -6
View File
@@ -79,7 +79,7 @@ func RpcHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
log.Errorf("Error get JSON body: %s", e)
}
default:
httperrors.InvalidInputError(w, fmt.Sprintf("Unsupported RPC method %s", req.Method))
httperrors.InvalidInputError(ctx, w, fmt.Sprintf("Unsupported RPC method %s", req.Method))
return
}
token := AppContextToken(ctx)
@@ -91,13 +91,13 @@ func RpcHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
if e != nil {
log.Debugf("module %s not found %s", resType, e)
}
httperrors.NotFoundError(w, fmt.Sprintf("resource %s not exists", resType))
httperrors.NotFoundError(ctx, w, fmt.Sprintf("resource %s not exists", resType))
return
}
modvalue := reflect.ValueOf(mod)
funcvalue := modvalue.MethodByName(funcname)
if !funcvalue.IsValid() || funcvalue.IsNil() {
httperrors.NotFoundError(w, fmt.Sprintf("RPC method %s not found", funcname))
httperrors.NotFoundError(ctx, w, fmt.Sprintf("RPC method %s not found", funcname))
return
}
callParams := make([]reflect.Value, 0)
@@ -127,14 +127,14 @@ func RpcHandler(ctx context.Context, w http.ResponseWriter, req *http.Request) {
return
}
httperrors.BadGatewayError(w, "recv invalid data")
httperrors.BadGatewayError(ctx, w, "recv invalid data")
} else {
v, ok := reterr.Interface().(*httputils.JSONClientError)
if ok {
httperrors.JsonClientError(w, v)
httperrors.JsonClientError(ctx, w, v)
return
}
httperrors.BadGatewayError(w, fmt.Sprintf("%s", reterr.Interface()))
httperrors.BadGatewayError(ctx, w, fmt.Sprintf("%s", reterr.Interface()))
}
}
+8 -7
View File
@@ -283,6 +283,7 @@ func (app *Application) defaultHandle(w http.ResponseWriter, r *http.Request, ri
if cancel != nil {
defer cancel()
}
ctx = httperrors.WithRequestLang(ctx, r)
session := hand.workerMan
if session == nil {
if r.Method == "GET" || r.Method == "HEAD" {
@@ -321,7 +322,7 @@ func (app *Application) defaultHandle(w http.ResponseWriter, r *http.Request, ri
},
currentWorker,
func(err error) {
httperrors.InternalServerError(&fw, "Internal server error: %s", err)
httperrors.InternalServerError(ctx, &fw, "Internal server error: %s", err)
fw.closeChannels()
},
)
@@ -330,20 +331,20 @@ func (app *Application) defaultHandle(w http.ResponseWriter, r *http.Request, ri
switch runErr.(type) {
case *httputils.JSONClientError:
je := runErr.(*httputils.JSONClientError)
httperrors.GeneralServerError(w, je)
httperrors.GeneralServerError(ctx, w, je)
default:
httperrors.InternalServerError(w, "Internal server error")
httperrors.InternalServerError(ctx, w, "Internal server error")
}
}
fw.closeChannels()
return hand, appParams
} else {
log.Errorf("Invalid handler for %s", r.URL)
httperrors.InternalServerError(w, "Invalid handler %s", r.URL)
ctx := httperrors.WithRequestLang(context.TODO(), r)
httperrors.InternalServerError(ctx, w, "Invalid handler %s", r.URL)
}
} else if !isCors {
log.Errorf("Handler not found")
httperrors.NotFoundError(w, "Handler not found")
ctx := httperrors.WithRequestLang(context.TODO(), r)
httperrors.NotFoundError(ctx, w, "Handler not found")
}
return nil, nil
}
+31 -66
View File
@@ -203,7 +203,7 @@ func listHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
func handleList(ctx context.Context, w http.ResponseWriter, manager IModelDispatchHandler, ctxIds []SResourceContext, query jsonutils.JSONObject) {
listResult, err := manager.List(ctx, query, ctxIds)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, modulebase.ListResult2JSONWithKey(listResult, manager.KeywordPlural()))
@@ -272,7 +272,7 @@ func getHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
result, err := manager.Get(ctx, params["<resid>"], mergeQueryParams(params, query, "<resid>"), false)
if err != nil {
e := httperrors.NewGeneralError(err)
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
if result != nil {
@@ -285,7 +285,7 @@ func getSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
result, err := manager.GetSpecific(ctx, params["<resid>"], params["<spec>"], mergeQueryParams(params, query, "<resid>", "<spec>"))
if err != nil {
e := httperrors.NewGeneralError(err)
httperrors.JsonClientError(w, e)
httperrors.JsonClientError(ctx, w, e)
return
}
if result != nil {
@@ -293,6 +293,18 @@ func getSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
}
}
func writeErrNoRequestKey(ctx context.Context, w http.ResponseWriter, r *http.Request, key string) {
ctx = httperrors.WithRequestLang(ctx, r)
httperrors.InvalidInputError(ctx, w,
"No request key: %s", key)
}
func writeErrInvalidRequestHeader(ctx context.Context, w http.ResponseWriter, r *http.Request, err error) {
ctx = httperrors.WithRequestLang(ctx, r)
httperrors.InvalidInputError(ctx, w,
"Invalid request header: %v", err)
}
func createHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
manager, params, query, body := fetchEnv(ctx, w, r)
handleCreate(ctx, w, manager, nil, mergeQueryParams(params, query), body, r)
@@ -306,29 +318,27 @@ func handleCreate(ctx context.Context, w http.ResponseWriter, manager IModelDisp
count, _ = body.Int("count")
data, err = body.Get(manager.Keyword())
if err != nil {
httperrors.InvalidInputError(w,
fmt.Sprintf("No request key: %s", manager.Keyword()))
writeErrNoRequestKey(ctx, w, r, manager.Keyword())
return
}
} else {
data, err = manager.FetchCreateHeaderData(ctx, r.Header)
if err != nil {
httperrors.InvalidInputError(w,
fmt.Sprintf("In valid request header: %s", err))
writeErrInvalidRequestHeader(ctx, w, r, err)
return
}
}
if count <= 1 {
result, err := manager.Create(ctx, query, data, ctxIds)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
} else {
results, err := manager.BatchCreate(ctx, query, data, int(count), ctxIds)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
ret := jsonutils.NewArray()
@@ -365,7 +375,7 @@ func performClassActionHandler(ctx context.Context, w http.ResponseWriter, r *ht
}
results, err := manager.PerformClassAction(ctx, params["<action>"], mergeQueryParams(params, query, "<action>"), data)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
if results == nil {
@@ -392,31 +402,13 @@ func performActionHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
}
result, err := manager.PerformAction(ctx, params["<resid>"], params["<action>"], mergeQueryParams(params, query, "<resid>", "<action>"), data)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
sendJSON(ctx, w, result, manager.Keyword())
// appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
}
/*
func updateClassHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
manager, _, query, body := fetchEnv(ctx, w, r)
data, err := body.Get(manager.KeywordPlural())
if err != nil {
httperrors.InvalidInputError(w,
fmt.Sprintf("No request key: %s", manager.KeywordPlural()))
return
}
result, err := manager.UpdateClass(ctx, tr, data)
if err != nil {
httperrors.GeneralServerError(w, err)
return
}
appsrv.SendJSON(w, wrapBody(result, manager.KeywordPlural()))
}
*/
func updateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
manager, params, query, body := fetchEnv(ctx, w, r)
handleUpdate(ctx, w, manager, params["<resid>"], nil, mergeQueryParams(params, query, "<resid>"), body, r)
@@ -429,8 +421,7 @@ func handleUpdate(ctx context.Context, w http.ResponseWriter, manager IModelDisp
if body.Contains(manager.Keyword()) {
data, err = body.Get(manager.Keyword())
if err != nil {
httperrors.InvalidInputError(w,
fmt.Sprintf("No request key: %s", manager.Keyword()))
writeErrNoRequestKey(ctx, w, r, manager.Keyword())
return
}
} else {
@@ -439,14 +430,13 @@ func handleUpdate(ctx context.Context, w http.ResponseWriter, manager IModelDisp
} else {
data, err = manager.FetchUpdateHeaderData(ctx, r.Header)
if err != nil {
httperrors.InvalidInputError(w,
fmt.Sprintf("In valid request header: %s", err))
writeErrInvalidRequestHeader(ctx, w, r, err)
return
}
}
result, err := manager.Update(ctx, resId, query, data, ctxIds)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
sendJSON(ctx, w, result, manager.Keyword())
@@ -468,8 +458,7 @@ func updateSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Reque
if body.Contains(manager.Keyword()) {
data, err = body.Get(manager.Keyword())
if err != nil {
httperrors.InvalidInputError(w,
fmt.Sprintf("No request key: %s", manager.Keyword()))
writeErrNoRequestKey(ctx, w, r, manager.Keyword())
return
}
} else {
@@ -478,41 +467,19 @@ func updateSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Reque
} else {
data, err = manager.FetchUpdateHeaderData(ctx, r.Header)
if err != nil {
httperrors.InvalidInputError(w,
fmt.Sprintf("In valid request header: %s", err))
writeErrInvalidRequestHeader(ctx, w, r, err)
return
}
}
result, err := manager.UpdateSpec(ctx, params["<resid>"], params["<spec>"], mergeQueryParams(params, query, "<resid>", "<spec>"), data)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
sendJSON(ctx, w, result, manager.Keyword())
// appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
}
/*
func deleteClassHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
tr, manager, _, query, body := fetchEnv(ctx, w, r)
var data jsonutils.JSONObject
if body != nil {
data, err := body.Get(manager.KeywordPlural())
if err != nil {
httperrors.InvalidInputError(w,
fmt.Sprintf("No request key: %s", manager.KeywordPlural()))
return
}
}
result, err := manager.DeleteClass(ctx, tr, query, data)
if err != nil {
httperrors.GeneralServerError(w, err)
return
}
appsrv.SendJSON(w, wrapBody(result, manager.KeywordPlural()))
}
*/
func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
manager, params, query, body := fetchEnv(ctx, w, r)
handleDelete(ctx, w, manager, params["<resid>"], nil, mergeQueryParams(params, query, "<resid>"), body, r)
@@ -525,8 +492,7 @@ func handleDelete(ctx context.Context, w http.ResponseWriter, manager IModelDisp
if body.Contains(manager.Keyword()) {
data, err = body.Get(manager.Keyword())
if err != nil {
httperrors.InvalidInputError(w,
fmt.Sprintf("No request key: %s", manager.Keyword()))
writeErrNoRequestKey(ctx, w, r, manager.Keyword())
return
}
} else {
@@ -537,7 +503,7 @@ func handleDelete(ctx context.Context, w http.ResponseWriter, manager IModelDisp
}
result, err := manager.Delete(ctx, resId, query, data, ctxIds)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
sendJSON(ctx, w, result, manager.Keyword())
@@ -559,8 +525,7 @@ func deleteSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Reque
if body.Contains(manager.Keyword()) {
data, err = body.Get(manager.Keyword())
if err != nil {
httperrors.InvalidInputError(w,
fmt.Sprintf("No request key: %s", manager.Keyword()))
writeErrNoRequestKey(ctx, w, r, manager.Keyword())
return
}
} else {
@@ -571,7 +536,7 @@ func deleteSpecHandler(ctx context.Context, w http.ResponseWriter, r *http.Reque
}
result, err := manager.DeleteSpec(ctx, params["<resid>"], params["<spec>"], mergeQueryParams(params, query, "<resid>", "<spec>"), data)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
sendJSON(ctx, w, result, manager.Keyword())
+7 -7
View File
@@ -118,7 +118,7 @@ func jointListHandler(ctx context.Context, w http.ResponseWriter, r *http.Reques
manager, params, query, _ := fetchJointEnv(ctx, w, r)
listResult, err := manager.List(ctx, mergeQueryParams(params, query), nil)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, modulebase.ListResult2JSONWithKey(listResult, manager.KeywordPlural()))
@@ -134,7 +134,7 @@ func jointListDescendentHandler(ctx context.Context, w http.ResponseWriter, r *h
listResult, err = manager.ListSlaveDescendent(ctx, params["<slave_id>"], mergeQueryParams(params, query, "<slave_id>"))
}
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, modulebase.ListResult2JSONWithKey(listResult, manager.KeywordPlural()))
@@ -144,7 +144,7 @@ func jointGetHandler(ctx context.Context, w http.ResponseWriter, r *http.Request
manager, params, query, _ := fetchJointEnv(ctx, w, r)
result, err := manager.Get(ctx, params["<master_id>"], params["<slave_id>"], mergeQueryParams(params, query, "<master_id>", "<slave_id>"))
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
@@ -162,7 +162,7 @@ func attachHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
}
result, err := manager.Attach(ctx, params["<master_id>"], params["<slave_id>"], mergeQueryParams(params, query, "<master_id>", "<slave_id>"), data)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
@@ -172,12 +172,12 @@ func updateJointHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
manager, params, query, body := fetchJointEnv(ctx, w, r)
data, err := body.Get(manager.Keyword())
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
result, err := manager.Update(ctx, params["<master_id>"], params["<slave_id>"], mergeQueryParams(params, query, "<master_id>", "<slave_id>"), data)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
@@ -191,7 +191,7 @@ func detachHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
}
result, err := manager.Detach(ctx, params["<master_id>"], params["<slave_id>"], mergeQueryParams(params, query, "<master_id>", "<slave_id>"), data)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, wrapBody(result, manager.Keyword()))
+1 -1
View File
@@ -261,7 +261,7 @@ func (ctx *Context) ResponseJson(obj jsonutils.JSONObject) {
}
func (ctx *Context) ResponseError(err error) {
httperrors.GeneralServerError(ctx.writer, err)
httperrors.GeneralServerError(ctx, ctx.writer, err)
}
func (ctx *Context) Request() *http.Request {
+9 -9
View File
@@ -274,8 +274,8 @@ func (i *BmRegisterInput) responseSucc(bmId string) {
close(i.C)
}
func (i *BmRegisterInput) responseErr(err error) {
httperrors.GeneralServerError(i.W, err)
func (i *BmRegisterInput) responseErr(ctx context.Context, err error) {
httperrors.GeneralServerError(ctx, i.W, err)
close(i.C)
}
@@ -294,7 +294,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
if input.isTimeout() {
return
} else if err != nil {
input.responseErr(httperrors.NewBadRequestError("Verify network failed: %s", err))
input.responseErr(ctx, httperrors.NewBadRequestError("Verify network failed: %s", err))
return
}
@@ -302,7 +302,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
if input.isTimeout() {
return
} else if err != nil {
input.responseErr(httperrors.NewBadRequestError("SSH verify failed: %s", err))
input.responseErr(ctx, httperrors.NewBadRequestError("SSH verify failed: %s", err))
return
}
@@ -311,7 +311,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
if input.isTimeout() {
return
} else if err != nil {
input.responseErr(httperrors.NewBadRequestError("Fetch ipmi address failed: %s", err))
input.responseErr(ctx, httperrors.NewBadRequestError("Fetch ipmi address failed: %s", err))
return
}
log.Infof("Find ipmi address %s", input.IpAddr)
@@ -320,7 +320,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
if input.isTimeout() {
return
} else if err != nil {
input.responseErr(httperrors.NewBadRequestError("Verify network failed: %s", err))
input.responseErr(ctx, httperrors.NewBadRequestError("Verify network failed: %s", err))
return
}
@@ -328,7 +328,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
if input.isTimeout() {
return
} else if err != nil {
input.responseErr(httperrors.NewBadRequestError("IPMI login info not correct: %s", err))
input.responseErr(ctx, httperrors.NewBadRequestError("IPMI login info not correct: %s", err))
return
}
@@ -336,7 +336,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
if input.isTimeout() {
return
} else if err != nil {
input.responseErr(httperrors.NewBadRequestError("Verify mac address failed: %s", err))
input.responseErr(ctx, httperrors.NewBadRequestError("Verify mac address failed: %s", err))
return
}
@@ -352,7 +352,7 @@ func (m *SBaremetalManager) RegisterBaremetal(ctx context.Context, userCred mccl
bmId, err = registerTask.UpdateBaremetal()
}
if err != nil {
input.responseErr(httperrors.NewInternalServerError(err.Error()))
input.responseErr(ctx, httperrors.NewInternalServerError("%v", err))
return
}
+1 -1
View File
@@ -50,7 +50,7 @@ func performImageCache(
disk, err := body.Get("disk")
if err != nil {
httperrors.MissingParameterError(w, "disk")
httperrors.MissingParameterError(ctx, w, "disk")
return
}
+1 -2
View File
@@ -16,7 +16,6 @@ package db
import (
"context"
"fmt"
"reflect"
"yunion.io/x/jsonutils"
@@ -109,7 +108,7 @@ func callObject(modelVal reflect.Value, fName string, inputs ...interface{}) ([]
func callFunc(funcVal reflect.Value, fName string, inputs ...interface{}) ([]reflect.Value, error) {
if !funcVal.IsValid() || funcVal.IsNil() {
return nil, httperrors.NewActionNotFoundError(fmt.Sprintf("%s method not found", fName))
return nil, httperrors.NewActionNotFoundError("%s method not found", fName)
}
funcType := funcVal.Type()
paramLen := funcType.NumIn()
+7 -9
View File
@@ -1165,7 +1165,7 @@ func _doCreateItem(
err = jsonutils.CheckRequiredFields(dataDict, createRequireFields(manager, userCred))
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
model, err := NewModelObject(manager)
if err != nil {
@@ -1398,7 +1398,7 @@ func (dispatcher *DBModelDispatcher) BatchCreate(ctx context.Context, query json
body, err := getItemDetails(manager, res.model, ctx, userCred, query)
if err != nil {
result.Status = 500
result.Data = jsonutils.NewString(err.Error())
result.Data = jsonutils.NewString(err.Error()) // no translation here
} else {
result.Status = 200
result.Data = body
@@ -1535,9 +1535,8 @@ func reflectDispatcherInternal(
if !funcValue.IsValid() || funcValue.IsNil() {
funcValue = modelValue.MethodByName(generalFuncName)
if !funcValue.IsValid() || funcValue.IsNil() {
msg := fmt.Sprintf("%s %s %s not found", dispatcher.Keyword(), operator, spec)
log.Errorf(msg)
return nil, httperrors.NewActionNotFoundError(msg)
return nil, httperrors.NewActionNotFoundError("%s %s %s not found",
dispatcher.Keyword(), operator, spec)
} else {
isGeneral = true
funcName = generalFuncName
@@ -1572,9 +1571,8 @@ func reflectDispatcherInternal(
allowFuncName := "Allow" + funcName
allowFuncValue := modelValue.MethodByName(allowFuncName)
if !allowFuncValue.IsValid() || allowFuncValue.IsNil() {
msg := fmt.Sprintf("%s allow %s %s not found", dispatcher.Keyword(), operator, spec)
log.Errorf(msg)
return nil, httperrors.NewActionNotFoundError(msg)
return nil, httperrors.NewActionNotFoundError("%s allow %s %s not found",
dispatcher.Keyword(), operator, spec)
}
outs, err := callFunc(allowFuncValue, allowFuncName, params...)
@@ -1741,7 +1739,7 @@ func deleteItem(manager IModelManager, model IModel, ctx context.Context, userCr
err = CustomizeDelete(model, ctx, userCred, query, data)
if err != nil {
log.Errorf("customize delete error: %s", err)
return nil, httperrors.NewNotAcceptableError(err.Error())
return nil, httperrors.NewNotAcceptableError("%v", err)
}
details, err := getItemDetails(manager, model, ctx, userCred, query)
+2 -1
View File
@@ -387,7 +387,8 @@ func FetchCheckQueryOwnerScope(ctx context.Context, userCred mcclient.TokenCrede
requireScope = queryScope
}
if doCheckRbac && requireScope.HigherThan(allowScope) {
return nil, scope, httperrors.NewForbiddenError(fmt.Sprintf("not enough privilege(require:%s,allow:%s,query:%s)", requireScope, allowScope, queryScope))
return nil, scope, httperrors.NewForbiddenError("not enough privilege (require:%s,allow:%s,query:%s)",
requireScope, allowScope, queryScope)
}
return ownerId, queryScope, nil
}
+1 -1
View File
@@ -37,7 +37,7 @@ func AddScopeResourceCountHandler(prefix string, app *appsrv.Application) {
func getAllScopeResourceCountsHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
cnt, err := getAllScopeResourceCounts()
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, jsonutils.Marshal(cnt))
+21 -21
View File
@@ -186,7 +186,7 @@ func (manager *SQuotaBaseManager) getQuotaHandler(ctx context.Context, w http.Re
}
ownerId, scope, err = db.FetchCheckQueryOwnerScope(ctx, userCred, data, manager.GetIQuotaManager(), policy.PolicyActionGet, true)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
} else {
@@ -206,7 +206,7 @@ func (manager *SQuotaBaseManager) getQuotaHandler(ctx context.Context, w http.Re
primary := jsonutils.QueryBoolean(query, "primary", false)
quotaList, err := manager.listQuotas(ctx, userCred, keys.DomainId, keys.ProjectId, scope == rbacutils.ScopeDomain, primary, refresh)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
if len(quotaList) == 0 {
@@ -223,7 +223,7 @@ func (manager *SQuotaBaseManager) getQuotaHandler(ctx context.Context, w http.Re
quotaList, err = manager.listQuotas(ctx, userCred, keys.DomainId, keys.ProjectId, scope == rbacutils.ScopeDomain, primary, refresh)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
}
@@ -301,7 +301,7 @@ func (manager *SQuotaBaseManager) cleanPendingUsageHandler(ctx context.Context,
}
ownerId, scope, err = db.FetchCheckQueryOwnerScope(ctx, userCred, data, manager, policy.PolicyActionGet, true)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
} else {
@@ -323,7 +323,7 @@ func (manager *SQuotaBaseManager) cleanPendingUsageHandler(ctx context.Context,
}
err = manager.cleanPendingUsage(ctx, userCred, keys)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
rbody := jsonutils.NewDict()
@@ -347,7 +347,7 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
err := body.Unmarshal(quota, manager.KeywordPlural())
if err != nil {
log.Errorf("Fail to decode JSON request body: %s", err)
httperrors.InvalidInputError(w, "fail to decode body")
httperrors.InvalidInputError(httperrors.WithRequestLang(ctx, r), w, "fail to decode body")
return
}
@@ -360,7 +360,7 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
}
ownerId, scope, requestScope, err := manager.fetchSetQuotaScope(ctx, userCred, data, isBaseQuota)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -381,7 +381,7 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
if err != nil {
if errors.Cause(err) != sql.ErrNoRows {
log.Errorf("get quota %s fail %s", QuotaKeyString(keys), err)
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
} else {
isNew = true
@@ -393,11 +393,11 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
if action == QUOTA_ACTION_DELETE {
if isNew {
// no need to delete
httperrors.NotFoundError(w, "Quota %s not found", QuotaKeyString(keys))
httperrors.NotFoundError(ctx, w, "Quota %s not found", QuotaKeyString(keys))
return
} else if isBaseQuota {
// base quota is not deletable
httperrors.ForbiddenError(w, "Default quota %s not allow to delete", QuotaKeyString(keys))
httperrors.ForbiddenError(ctx, w, "Default quota %s not allow to delete", QuotaKeyString(keys))
return
}
policyAction = policy.PolicyActionDelete
@@ -414,14 +414,14 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
// check rbac policy
ownerScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policyAction)
if requestScope.HigherThan(ownerScope) {
httperrors.ForbiddenError(w, "not enough privilleges")
httperrors.ForbiddenError(ctx, w, "not enough privilleges")
return
}
if action == QUOTA_ACTION_DELETE {
err = manager.DeleteQuota(ctx, userCred, keys)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
} else {
@@ -445,14 +445,14 @@ func (manager *SQuotaBaseManager) setQuotaHandler(ctx context.Context, w http.Re
err = manager.SetQuota(ctx, userCred, oquota)
if err != nil {
log.Errorf("set quota fail %s", err)
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
}
quotaList, err := manager.listQuotas(ctx, userCred, baseKeys.OwnerId().GetProjectDomainId(), baseKeys.OwnerId().GetProjectId(), scope == rbacutils.ScopeDomain, false, true)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
manager.sendQuotaList(w, quotaList)
@@ -465,12 +465,12 @@ func (manager *SQuotaBaseManager) listDomainQuotaHandler(ctx context.Context, w
if consts.IsRbacEnabled() {
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionList)
if allowScope != rbacutils.ScopeSystem {
httperrors.ForbiddenError(w, "not allow to list domain quotas")
httperrors.ForbiddenError(ctx, w, "not allow to list domain quotas")
return
}
} else {
if !userCred.HasSystemAdminPrivilege() {
httperrors.ForbiddenError(w, "out of privileges")
httperrors.ForbiddenError(ctx, w, "out of privileges")
return
}
}
@@ -479,7 +479,7 @@ func (manager *SQuotaBaseManager) listDomainQuotaHandler(ctx context.Context, w
primary := jsonutils.QueryBoolean(query, "primary", false)
quotaList, err := manager.listQuotas(ctx, userCred, "", "", false, primary, refresh)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
manager.sendQuotaList(w, sortQuotaByUsage(quotaList))
@@ -496,7 +496,7 @@ func (manager *SQuotaBaseManager) listProjectQuotaHandler(ctx context.Context, w
_, query, _ := appsrv.FetchEnv(ctx, w, r)
owner, err := db.FetchDomainInfo(ctx, query)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
if owner == nil {
@@ -507,12 +507,12 @@ func (manager *SQuotaBaseManager) listProjectQuotaHandler(ctx context.Context, w
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionList)
if (allowScope == rbacutils.ScopeDomain && userCred.GetProjectDomainId() == owner.GetProjectDomainId()) || allowScope == rbacutils.ScopeSystem {
} else {
httperrors.ForbiddenError(w, "not allow to list project quotas")
httperrors.ForbiddenError(ctx, w, "not allow to list project quotas")
return
}
} else {
if !userCred.HasSystemAdminPrivilege() {
httperrors.ForbiddenError(w, "out of privileges")
httperrors.ForbiddenError(ctx, w, "out of privileges")
return
}
}
@@ -522,7 +522,7 @@ func (manager *SQuotaBaseManager) listProjectQuotaHandler(ctx context.Context, w
primary := jsonutils.QueryBoolean(query, "primary", false)
quotaList, err := manager.listQuotas(ctx, userCred, domainId, "", false, primary, refresh)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
manager.sendQuotaList(w, sortQuotaByUsage(quotaList))
+2 -4
View File
@@ -15,8 +15,6 @@
package db
import (
"fmt"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/httperrors"
@@ -72,7 +70,7 @@ func isObjectRbacAllowed(model IModel, userCred mcclient.TokenCredential, action
if !requireScope.HigherThan(scope) {
return nil
}
return httperrors.NewForbiddenError(fmt.Sprintf("not enough privilege(require:%s,allow:%s:resource:%s)", requireScope, scope, resScope))
return httperrors.NewForbiddenError("not enough privilege (require:%s,allow:%s:resource:%s)", requireScope, scope, resScope)
}
func isJointObjectRbacAllowed(item IJointModel, userCred mcclient.TokenCredential, action string, extra ...string) error {
@@ -124,7 +122,7 @@ func isClassRbacAllowed(manager IModelManager, userCred mcclient.TokenCredential
if !requireScope.HigherThan(allowScope) {
return nil
}
return httperrors.NewForbiddenError(fmt.Sprintf("not enough privilege(require:%s,allow:%s)", requireScope, allowScope))
return httperrors.NewForbiddenError("not enough privilege (require:%s,allow:%s)", requireScope, allowScope)
}
type IResource interface {
+2 -2
View File
@@ -111,11 +111,11 @@ func newInvalidIntChoiceError(key string, choices []int64, choice int64) error {
}
func newStringTooShortError(key string, got, want int) error {
return newError(ERR_INVALID_LENGTH, "%q too short, got %d, min %s", key, got, want)
return newError(ERR_INVALID_LENGTH, "%q too short, got %d, min %d", key, got, want)
}
func newStringTooLongError(key string, got, want int) error {
return newError(ERR_INVALID_LENGTH, "%q too long, got %d, max %s", key, got, want)
return newError(ERR_INVALID_LENGTH, "%q too long, got %d, max %d", key, got, want)
}
func newNotInRangeError(key string, value, lower, upper int64) error {
+2 -2
View File
@@ -36,12 +36,12 @@ func capaHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
capa, err := models.GetCapabilities(ctx, userCred, query, nil, nil)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, jsonutils.Marshal(capa))
+4 -6
View File
@@ -20,7 +20,6 @@ import (
"net"
"net/http"
"yunion.io/x/log"
"yunion.io/x/pkg/tristate"
"yunion.io/x/onecloud/pkg/apis/compute"
@@ -56,14 +55,14 @@ func getBmAgentUrl(ctx context.Context, w http.ResponseWriter, r *http.Request)
n, _ := models.NetworkManager.GetOnPremiseNetworkOfIP(ipAddr, "", tristate.None)
if n == nil {
httperrors.NotFoundError(w, "Network not found")
httperrors.NotFoundError(ctx, w, "Network not found")
return
}
zoneId := n.GetWire().ZoneId
bmAgent := models.BaremetalagentManager.GetAgent(compute.AgentTypeBaremetal, zoneId)
if bmAgent == nil {
httperrors.InternalServerError(w, "Baremetal agent not found")
httperrors.InternalServerError(ctx, w, "Baremetal agent not found")
return
}
@@ -72,13 +71,12 @@ func getBmAgentUrl(ctx context.Context, w http.ResponseWriter, r *http.Request)
func getBmPrepareScript(ctx context.Context, w http.ResponseWriter, r *http.Request) {
if len(options.Options.BaremetalPreparePackageUrl) == 0 {
httperrors.NotAcceptableError(w, "Baremetal package not prepared")
httperrors.NotAcceptableError(ctx, w, "Baremetal package not prepared")
return
}
regionUrl, err := auth.GetPublicServiceURL("compute_v2", options.Options.Region, "")
if err != nil {
log.Errorln(err)
httperrors.InternalServerError(w, err.Error())
httperrors.InternalServerError(ctx, w, "%v", err)
return
}
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
+3 -3
View File
@@ -532,7 +532,7 @@ func (manager *SDiskManager) validateDiskOnStorage(diskConfig *api.DiskConfig, s
if host := storage.GetMasterHost(); host != nil {
//公有云磁盘大小检查。
if err := host.GetHostDriver().ValidateDiskSize(storage, diskConfig.SizeMb>>10); err != nil {
return httperrors.NewInputParameterError(err.Error())
return httperrors.NewInputParameterError("%v", err)
}
}
hoststorages := HoststorageManager.Query().SubQuery()
@@ -916,7 +916,7 @@ func (disk *SDisk) doResize(ctx context.Context, userCred mcclient.TokenCredenti
}
if host := storage.GetMasterHost(); host != nil {
if err := host.GetHostDriver().ValidateDiskSize(storage, sizeMb>>10); err != nil {
return httperrors.NewInputParameterError(err.Error())
return httperrors.NewInputParameterError("%v", err)
}
}
if int64(addDisk) > storage.GetFreeCapacity() && !storage.IsEmulated {
@@ -924,7 +924,7 @@ func (disk *SDisk) doResize(ctx context.Context, userCred mcclient.TokenCredenti
}
if guest != nil {
if err := guest.ValidateResizeDisk(disk, storage); err != nil {
return httperrors.NewInputParameterError(err.Error())
return httperrors.NewInputParameterError("%v", err)
}
}
pendingUsage := SQuota{Storage: int(addDisk)}
+1 -1
View File
@@ -1345,7 +1345,7 @@ func (self *SElasticip) PerformChangeBandwidth(ctx context.Context, userCred mcc
}
if err := factory.ValidateChangeBandwidth(self.AssociateId, bandwidth); err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
}
+1 -1
View File
@@ -214,7 +214,7 @@ func (group *SGroup) ValidateDeleteCondition(ctx context.Context) error {
return errors.Wrapf(err, "fail to check that if there are any guest in this group %s", group.Name)
}
if count > 0 {
return httperrors.NewUnsupportOperationError("请在解绑所有主机后重试")
return httperrors.NewUnsupportOperationError("please retry after unbind all guests in group")
}
return nil
}
+26 -26
View File
@@ -582,7 +582,7 @@ func (self *SGuest) PerformDeploy(ctx context.Context, userCred mcclient.TokenCr
})
if err != nil {
log.Errorf("update keypair fail: %s", err)
return nil, httperrors.NewInternalServerError(err.Error())
return nil, httperrors.NewInternalServerError("%v", err)
}
db.OpsLog.LogEvent(self, db.ACT_UPDATE, diff, userCred)
@@ -615,7 +615,7 @@ func (self *SGuest) PerformDeploy(ctx context.Context, userCred mcclient.TokenCr
deployStatus, err := self.GetDriver().GetDeployStatus()
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
if utils.IsInStringArray(self.Status, deployStatus) {
@@ -1427,7 +1427,7 @@ func (self *SGuest) PerformRebuildRoot(ctx context.Context, userCred mcclient.To
rebuildStatus, err := self.GetDriver().GetRebuildRootStatus()
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
if !self.GetDriver().IsRebuildRootSupportChangeImage() && len(imageId) > 0 {
@@ -1569,7 +1569,7 @@ func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.Tok
diskInfo, err := parseDiskInfo(ctx, userCred, diskDefArray[diskIdx])
if err != nil {
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_CREATE, err.Error(), userCred, false)
return nil, httperrors.NewBadRequestError(err.Error())
return nil, httperrors.NewBadRequestError("%v", err)
}
if len(diskInfo.Backend) == 0 {
diskInfo.Backend = self.getDefaultStorageType()
@@ -1609,7 +1609,7 @@ func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.Tok
err = quotas.CheckSetPendingQuota(ctx, userCred, pendingUsage)
if err != nil {
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_CREATE, err.Error(), userCred, false)
return nil, httperrors.NewOutOfQuotaError(err.Error())
return nil, httperrors.NewOutOfQuotaError("%v", err)
}
lockman.LockObject(ctx, host)
@@ -1619,7 +1619,7 @@ func (self *SGuest) PerformCreatedisk(ctx context.Context, userCred mcclient.Tok
if err != nil {
quotas.CancelPendingUsage(ctx, userCred, pendingUsage, pendingUsage, false)
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_CREATE, err.Error(), userCred, false)
return nil, httperrors.NewBadRequestError(err.Error())
return nil, httperrors.NewBadRequestError("%v", err)
}
err = self.StartGuestCreateDiskTask(ctx, userCred, disksConf, "")
return nil, err
@@ -1755,9 +1755,10 @@ func (self *SGuest) PerformDetachIsolatedDevice(ctx context.Context, userCred mc
func (self *SGuest) startDetachIsolateDevice(ctx context.Context, userCred mcclient.TokenCredential, device string) error {
iDev, err := IsolatedDeviceManager.FetchByIdOrName(userCred, device)
if err != nil {
msg := fmt.Sprintf("Isolated device %s not found", device)
msgFmt := "Isolated device %s not found"
msg := fmt.Sprintf(msgFmt, device)
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_DETACH_ISOLATED_DEVICE, msg, userCred, false)
return httperrors.NewBadRequestError(msg)
return httperrors.NewBadRequestError(msgFmt, device)
}
dev := iDev.(*SIsolatedDevice)
host := self.GetHost()
@@ -1848,9 +1849,10 @@ func (self *SGuest) startAttachIsolatedDevices(ctx context.Context, userCred mcc
func (self *SGuest) startAttachIsolatedDevice(ctx context.Context, userCred mcclient.TokenCredential, device string) error {
iDev, err := IsolatedDeviceManager.FetchByIdOrName(userCred, device)
if err != nil {
msg := fmt.Sprintf("Isolated device %s not found", device)
msgFmt := "Isolated device %s not found"
msg := fmt.Sprintf(msgFmt, device)
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_GUEST_ATTACH_ISOLATED_DEVICE, msg, userCred, false)
return httperrors.NewBadRequestError(msg)
return httperrors.NewBadRequestError(msgFmt, device)
}
dev := iDev.(*SIsolatedDevice)
host := self.GetHost()
@@ -2062,7 +2064,7 @@ func (self *SGuest) PerformChangeIpaddr(ctx context.Context, userCred mcclient.T
if err2 != nil {
log.Errorf("recover detached network fail %s", err2)
}
return nil, httperrors.NewBadRequestError(err.Error())
return nil, httperrors.NewBadRequestError("%v", err)
}
return ngn, nil
@@ -2188,7 +2190,7 @@ func (self *SGuest) PerformAttachnetwork(ctx context.Context, userCred mcclient.
pendingUsage.SetKeys(keys)
err = quotas.CheckSetPendingQuota(ctx, userCred, pendingUsage)
if err != nil {
return nil, httperrors.NewOutOfQuotaError(err.Error())
return nil, httperrors.NewOutOfQuotaError("%v", err)
}
host := self.GetHost()
defer host.ClearSchedDescCache()
@@ -2197,7 +2199,7 @@ func (self *SGuest) PerformAttachnetwork(ctx context.Context, userCred mcclient.
logclient.AddSimpleActionLog(self, logclient.ACT_ATTACH_NETWORK, input.Nets[i], userCred, err == nil)
if err != nil {
quotas.CancelPendingUsage(ctx, userCred, pendingUsage, pendingUsage, false)
return nil, httperrors.NewBadRequestError(err.Error())
return nil, httperrors.NewBadRequestError("%v", err)
}
}
@@ -2218,8 +2220,7 @@ func (self *SGuest) AllowPerformChangeBandwidth(ctx context.Context, userCred mc
func (self *SGuest) PerformChangeBandwidth(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if !utils.IsInStringArray(self.Status, []string{api.VM_READY, api.VM_RUNNING}) {
msg := fmt.Sprintf("Cannot change bandwidth in status %s", self.Status)
return nil, httperrors.NewBadRequestError(msg)
return nil, httperrors.NewBadRequestError("Cannot change bandwidth in status %s", self.Status)
}
bandwidth, err := data.Int("bandwidth")
@@ -2256,8 +2257,7 @@ func (self *SGuest) AllowPerformModifySrcCheck(ctx context.Context, userCred mcc
func (self *SGuest) PerformModifySrcCheck(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if !utils.IsInStringArray(self.Status, []string{api.VM_READY, api.VM_RUNNING}) {
msg := fmt.Sprintf("Cannot change seting in status %s", self.Status)
return nil, httperrors.NewBadRequestError(msg)
return nil, httperrors.NewBadRequestError("Cannot change setting in status %s", self.Status)
}
argValue := func(name string, val *bool) error {
@@ -2319,7 +2319,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
changeStatus, err := self.GetDriver().GetChangeConfigStatus(self)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
if !utils.IsInStringArray(self.Status, changeStatus) {
return nil, httperrors.NewInvalidStatusError("Cannot change config in %s", self.Status)
@@ -2463,7 +2463,7 @@ func (self *SGuest) PerformChangeConfig(ctx context.Context, userCred mcclient.T
}
err = self.ValidateResizeDisk(disk, storage)
if err != nil {
return nil, httperrors.NewUnsupportOperationError(err.Error())
return nil, httperrors.NewUnsupportOperationError("%v", err)
}
if !storage.IsEmulated && storage.GetFreeCapacity() < int64(addDisk) {
return nil, httperrors.NewInsufficientResourceError("Not enough free space")
@@ -2793,7 +2793,7 @@ func (self *SGuest) PerformSendkeys(ctx context.Context, userCred mcclient.Token
}
err = self.VerifySendKeys(keys)
if err != nil {
return nil, httperrors.NewBadRequestError(err.Error())
return nil, httperrors.NewBadRequestError("%v", err)
}
cmd := fmt.Sprintf("sendkey %s", keys)
duration, err := data.Int("duration")
@@ -3435,7 +3435,7 @@ func (self *SGuest) StartGuestCreateBackupTask(
req.SetKeys(keys)
err = quotas.CheckSetPendingQuota(ctx, userCred, &req)
if err != nil {
return nil, httperrors.NewOutOfQuotaError(err.Error())
return nil, httperrors.NewOutOfQuotaError("%v", err)
}
params := data.(*jsonutils.JSONDict)
@@ -4232,11 +4232,11 @@ func (self *SGuest) PerformSyncFixNics(ctx context.Context,
}
}
if len(errs) > 0 {
return nil, httperrors.NewInvalidStatusError(errors.NewAggregate(errs).Error())
return nil, httperrors.NewInvalidStatusError("%v", errors.NewAggregate(errs))
}
result := self.SyncVMNics(ctx, userCred, host, vnics, iplist)
if result.IsError() {
return nil, httperrors.NewInternalServerError(result.Result())
return nil, httperrors.NewInternalServerError("%s", result.Result())
}
return nil, nil
}
@@ -4425,7 +4425,7 @@ func (manager *SGuestManager) PerformBatchMigrate(ctx context.Context, userCred
q := GuestManager.Query().In("id", params.GuestIds)
err = db.FetchModelObjects(GuestManager, q, &guests)
if err != nil {
return nil, httperrors.NewInternalServerError(err.Error())
return nil, httperrors.NewInternalServerError("%v", err)
}
if len(guests) != len(params.GuestIds) {
return nil, httperrors.NewBadRequestError("Check input guests is exist")
@@ -4530,7 +4530,7 @@ func (self *SGuest) validateCreateInstanceSnapshot(
if storage := disks[i].GetDisk().GetStorage(); utils.IsInStringArray(storage.StorageType, api.FIEL_STORAGE) {
count, err := SnapshotManager.GetDiskManualSnapshotCount(disks[i].DiskId)
if err != nil {
return nil, httperrors.NewInternalServerError(err.Error())
return nil, httperrors.NewInternalServerError("%v", err)
}
if count >= options.Options.DefaultMaxManualSnapshotCount {
return nil, httperrors.NewBadRequestError("guests disk %d snapshot full, can't take anymore", i)
@@ -4600,7 +4600,7 @@ func (self *SGuest) PerformInstanceSnapshotReset(
) (jsonutils.JSONObject, error) {
if self.Status != api.VM_READY {
return nil, httperrors.NewInvalidStatusError("guest can't do snapshot in status ", self.Status)
return nil, httperrors.NewInvalidStatusError("guest can't do snapshot in status %s", self.Status)
}
dataDict := data.(*jsonutils.JSONDict)
+15 -9
View File
@@ -195,7 +195,7 @@ func Brand2Hypervisor(brand string) string {
func (gtm *SGuestTemplateManager) validateContent(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, content *jsonutils.JSONDict) (*computeapis.ServerCreateInput, error) {
input, err := GuestManager.validateCreateData(ctx, userCred, ownerId, query, content)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
// check Image
imageId := input.Disks[0].ImageId
@@ -230,7 +230,7 @@ func (gtm *SGuestTemplateManager) validateData(
copy := jsonutils.DeepCopy(content).(*jsonutils.JSONDict)
input, err := gtm.validateContent(ctx, userCred, ownerId, query, copy)
if err != nil {
return cinput, httperrors.NewInputParameterError(err.Error())
return cinput, httperrors.NewInputParameterError("%v", err)
}
log.Debugf("data: %#v", input)
// fill field
@@ -582,16 +582,22 @@ func (gt *SGuestTemplate) PerformPublic(
}
func (gt *SGuestTemplate) genForbiddenError(resourceName, resourceStr, scope string) error {
var msg string
if len(resourceStr) == 0 {
msg = fmt.Sprintf("the %s in guest template is not a public resource", resourceName)
var (
msgFmt string
msgArgs []interface{}
)
if resourceStr == "" {
msgFmt = "the %s in guest template is not a public resource"
msgArgs = []interface{}{resourceName}
} else {
msg = fmt.Sprintf("the %s '%s' in guest template is not a public resource", resourceName, resourceStr)
msgFmt = "the %s %q in guest template is not a public resource"
msgArgs = []interface{}{resourceName, resourceStr}
}
if len(scope) > 0 {
msg += fmt.Sprintf(" in %s scope", scope)
if scope != "" {
msgFmt += " in %s scope"
msgArgs = append(msgArgs, scope)
}
return httperrors.NewForbiddenError(msg)
return httperrors.NewForbiddenError(msgFmt, msgArgs...)
}
func (gt *SGuestTemplate) ValidateDeleteCondition(ctx context.Context) error {
+3 -3
View File
@@ -939,7 +939,7 @@ func (self *SGuest) ValidateUpdateData(ctx context.Context, userCred mcclient.To
if vcpuCount > 0 || vmemSize > 0 {
quota, err := self.checkUpdateQuota(ctx, userCred, vcpuCount, vmemSize)
if err != nil {
return nil, httperrors.NewOutOfQuotaError(err.Error())
return nil, httperrors.NewOutOfQuotaError("%v", err)
}
if !quota.IsEmpty() {
data.Add(jsonutils.Marshal(quota), "pending_usage")
@@ -3553,7 +3553,7 @@ func (self *SGuest) LeaveAllGroups(ctx context.Context, userCred mcclient.TokenC
q := GroupguestManager.Query()
err := q.Filter(sqlchemy.Equals(q.Field("guest_id"), self.Id)).All(&groupGuests)
if err != nil {
log.Errorln(err.Error())
log.Errorf("query by guest_id %s: %v", self.Id, err)
return
}
for _, gg := range groupGuests {
@@ -3563,7 +3563,7 @@ func (self *SGuest) LeaveAllGroups(ctx context.Context, userCred mcclient.TokenC
gq := GroupManager.Query()
err := gq.Filter(sqlchemy.Equals(gq.Field("id"), gg.GroupId)).First(&group)
if err != nil {
log.Errorln(err.Error())
log.Errorf("get by group id %s: %v", gg.GroupId, err)
return
}
group.SetModelManager(GroupManager, &group)
+1 -1
View File
@@ -73,7 +73,7 @@ func (self *SGuest) PerformPrepaidRecycle(ctx context.Context, userCred mcclient
}
err := self.CanPerformPrepaidRecycle()
if err != nil {
return nil, httperrors.NewInvalidStatusError(err.Error())
return nil, httperrors.NewInvalidStatusError("%v", err)
}
return self.DoPerformPrepaidRecycle(ctx, userCred, jsonutils.QueryBoolean(data, "auto_delete", false))
+6 -6
View File
@@ -2856,7 +2856,7 @@ func (self *SHost) PostCreate(
return nil
})
if err != nil {
log.Errorln(err.Error())
log.Errorf("save updates: %v", err)
} else if len(ipmiInfo.IpAddr) > 0 {
self.setIpmiIp(userCred, ipmiInfo.IpAddr)
}
@@ -3977,13 +3977,13 @@ func (self *SHost) addNetif(ctx context.Context, userCred mcclient.TokenCredenti
if netif.NicType == api.NIC_TYPE_ADMIN {
err := self.setAccessMac(userCred, netif.Mac)
if err != nil {
return httperrors.NewBadRequestError(err.Error())
return httperrors.NewBadRequestError("%v", err)
}
}
if len(ipAddr) > 0 {
err = self.EnableNetif(ctx, userCred, netif, "", ipAddr, "", "", reserve, requireDesignatedIp)
if err != nil {
return httperrors.NewBadRequestError(err.Error())
return httperrors.NewBadRequestError("%v", err)
}
}
return nil
@@ -4014,7 +4014,7 @@ func (self *SHost) PerformEnableNetif(ctx context.Context, userCred mcclient.Tok
requireDesignatedIp := jsonutils.QueryBoolean(data, "require_designated_ip", false)
err := self.EnableNetif(ctx, userCred, netif, network, ipAddr, allocDir, netType, reserve, requireDesignatedIp)
if err != nil {
return nil, httperrors.NewBadRequestError(err.Error())
return nil, httperrors.NewBadRequestError("%v", err)
}
return nil, nil
}
@@ -4121,7 +4121,7 @@ func (self *SHost) PerformDisableNetif(ctx context.Context, userCred mcclient.To
reserve := jsonutils.QueryBoolean(data, "reserve", false)
err := self.DisableNetif(ctx, userCred, netif, reserve)
if err != nil {
return nil, httperrors.NewBadRequestError(err.Error())
return nil, httperrors.NewBadRequestError("%v", err)
}
return nil, nil
}
@@ -4510,7 +4510,7 @@ func (self *SHost) PerformUndoConvert(ctx context.Context, userCred mcclient.Tok
}
err := driver.PrepareUnconvert(self)
if err != nil {
return nil, httperrors.NewNotAcceptableError(err.Error())
return nil, httperrors.NewNotAcceptableError("%v", err)
}
guests := self.GetGuests()
if len(guests) > 1 {
+1 -1
View File
@@ -141,7 +141,7 @@ func (man *SNatDEntryManager) ValidateCreateData(ctx context.Context, userCred m
// check ip + port
eip, err := man.checkIPPort(input)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
// check that eip is suitable
+2 -2
View File
@@ -168,7 +168,7 @@ func (man *SNatSEntryManager) ValidateCreateData(ctx context.Context, userCred m
//check sourceCidr and convert to netutils.IPV4Range
sourceIPV4Range, err := newIPv4RangeFromCIDR(input.SourceCidr)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
// get natgateway
model, err := man.FetchById(input.NatgatewayId)
@@ -194,7 +194,7 @@ func (man *SNatSEntryManager) ValidateCreateData(ctx context.Context, userCred m
} else {
network, err := man.checkNetWorkId(input.NetworkId)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
data.Add(jsonutils.NewString(network.GetExternalId()), "network_ext_id")
}
+1 -1
View File
@@ -234,7 +234,7 @@ func (spm *SScalingPolicyManager) ValidateCreateData(ctx context.Context, userCr
}
input, err = trigger.ValidateCreateData(input)
if err != nil {
return input, httperrors.NewInputParameterError(err.Error())
return input, httperrors.NewInputParameterError("%v", err)
}
return input, err
}
+3 -3
View File
@@ -620,13 +620,13 @@ func (self *SSecurityGroup) PerformAddRule(ctx context.Context, userCred mcclien
PortEnd: -1,
}
if err := rule.ParsePorts(secgrouprule.Ports); err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
if err := rule.ValidateRule(); err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
if err := SecurityGroupRuleManager.TableSpec().Insert(ctx, secgrouprule); err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
self.DoSync(ctx, userCred)
return nil, nil
+2 -2
View File
@@ -363,12 +363,12 @@ func (self *SServerSkuManager) ValidateCreateData(ctx context.Context, userCred
// 格式 ecs.g1.c1m1
input.Name, err = genInstanceType(input.InstanceTypeFamily, input.CpuCoreCount, input.MemorySizeMB)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
q := self.Query().Equals("name", input.Name)
count, err := q.CountWithError()
if err != nil {
return nil, httperrors.NewGeneralError(fmt.Errorf("checkout server sku name duplicate error: %v", err))
return nil, httperrors.NewInternalServerError("checkout server sku name duplicate error: %v", err)
}
if count > 0 {
return nil, httperrors.NewDuplicateResourceError("Duplicate sku %s", input.Name)
+4 -4
View File
@@ -192,7 +192,7 @@ func (manager *SSnapshotPolicyManager) ValidateCreateData(ctx context.Context, u
}
input.RepeatWeekdays, err = validate.DaysCheck(input.RepeatWeekdays, 1, 7)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
if len(input.TimePoints) == 0 {
@@ -203,7 +203,7 @@ func (manager *SSnapshotPolicyManager) ValidateCreateData(ctx context.Context, u
}
input.TimePoints, err = validate.DaysCheck(input.TimePoints, 0, 23)
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
internalInput := manager.sSnapshotPolicyCreateInputToInternal(input)
@@ -275,7 +275,7 @@ func (sp *SSnapshotPolicy) UpdateParamCheck(input *api.SSnapshotPolicyCreateInpu
if input.RepeatWeekdays != nil && len(input.RepeatWeekdays) != 0 {
input.RepeatWeekdays, err = validate.DaysCheck(input.RepeatWeekdays, 1, 7)
if err != nil {
return httperrors.NewInputParameterError(err.Error())
return httperrors.NewInputParameterError("%v", err)
}
if sp.RepeatWeekdays != SnapshotPolicyManager.RepeatWeekdaysParseIntArray(input.RepeatWeekdays) {
updateNum++
@@ -285,7 +285,7 @@ func (sp *SSnapshotPolicy) UpdateParamCheck(input *api.SSnapshotPolicyCreateInpu
if input.TimePoints != nil && len(input.TimePoints) != 0 {
input.TimePoints, err = validate.DaysCheck(input.TimePoints, 0, 23)
if err != nil {
return httperrors.NewInputParameterError(err.Error())
return httperrors.NewInputParameterError("%v", err)
}
if sp.TimePoints != SnapshotPolicyManager.TimePointsParseIntArray(input.TimePoints) {
updateNum++
+1 -1
View File
@@ -25,7 +25,7 @@ import (
)
const (
errMappedIpExhausted = errors.Error("mapped ip exhaused")
errMappedIpExhausted = errors.Error("mapped ip exhausted")
LOCK_CLASS_guestnetworks_mapped_addr = "guestnetworks-mapped-addr"
LOCK_OBJ_guestnetworks_mapped_addr = "the-addr"
+3 -3
View File
@@ -767,7 +767,7 @@ func (self *SAliyunRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx cont
supportRegions = append(supportRegions, "Aliyun/"+region)
}
if !utils.IsInStringArray(cloudregion.ExternalId, supportRegions) {
return nil, httperrors.NewUnsupportOperationError("cloudregion %s(%d) not support %s scheduler", cloudregion.Name, cloudregion.Id, scheduler)
return nil, httperrors.NewUnsupportOperationError("cloudregion %s(%s) not support %s scheduler", cloudregion.Name, cloudregion.Id, scheduler)
}
}
@@ -1055,7 +1055,7 @@ func (self *SAliyunRegionDriver) ValidateCreateDBInstanceData(ctx context.Contex
return input, httperrors.NewInputParameterError("SQL Server cannot have more than seven read-only dbinstances")
}
default:
return input, httperrors.NewInputParameterError("Not support create readonly dbinstance which master dbinstance engine is", master.Engine)
return input, httperrors.NewInputParameterError("Not support create readonly dbinstance with master dbinstance engine %s", master.Engine)
}
}
@@ -1074,7 +1074,7 @@ func (self *SAliyunRegionDriver) ValidateCreateDBInstanceData(ctx context.Contex
return input, httperrors.NewGeneralError(err)
}
if count < 2 {
return input, httperrors.NewInputParameterError("At least two networks are required under vpc %s(%s) whith aliyun %s(%s)", vpc.Name, vpc.Id, input.Engine, input.Category)
return input, httperrors.NewInputParameterError("At least two networks are required under vpc %s(%s) with aliyun %s(%s)", vpc.Name, vpc.Id, input.Engine, input.Category)
}
}
}
+1 -1
View File
@@ -570,7 +570,7 @@ func (self *SAwsRegionDriver) ValidateUpdateLoadbalancerListenerData(ctx context
ownerId := lblis.GetOwnerId()
lb := lblis.GetLoadbalancer()
if lb == nil {
return nil, httperrors.NewResourceNotFoundError("loadbalancer listener %s related listener %s not found", lblis.Id, lblis.LoadbalancerId)
return nil, httperrors.NewResourceNotFoundError("loadbalancer listener %s related loadbalancer %s not found", lblis.Id, lblis.LoadbalancerId)
}
if lb.LoadbalancerSpec == api.LB_AWS_SPEC_APPLICATION {
+2 -2
View File
@@ -61,7 +61,7 @@ func processFilter(handleFunc specHandleFunc) appsrv.FilterHandler {
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
params := appctx.AppContextParams(ctx)
@@ -70,7 +70,7 @@ func processFilter(handleFunc specHandleFunc) appsrv.FilterHandler {
}
spec, err := handleFunc(ctx, userCred, query.(*jsonutils.JSONDict))
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
ret := jsonutils.NewDict()
+5 -5
View File
@@ -47,22 +47,22 @@ func adminSshKeysHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
params := appctx.AppContextParams(ctx)
projectId := params["<tenant_id>"]
if len(projectId) == 0 {
httperrors.InputParameterError(w, "empty project_id/tenant_id")
httperrors.InputParameterError(ctx, w, "empty project_id/tenant_id")
return
}
tenant, err := db.TenantCacheManager.FetchTenantByIdOrName(ctx, projectId)
if err != nil {
if err == sql.ErrNoRows {
httperrors.ResourceNotFoundError(w, "tenant/project %s not found", projectId)
httperrors.ResourceNotFoundError(ctx, w, "tenant/project %s not found", projectId)
return
} else {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
}
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
isAdmin := jsonutils.QueryBoolean(query, "admin", false)
@@ -74,7 +74,7 @@ func sshKeysHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
isAdmin := jsonutils.QueryBoolean(query, "admin", false)
+3 -3
View File
@@ -97,12 +97,12 @@ func rangeObjHandler(
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
obj, err := getRangeObj(ctx, manager, userCred)
if err != nil {
httperrors.NotFoundError(w, err.Error())
httperrors.NotFoundError(ctx, w, "%v", err)
return
}
ownerId, scope, err := db.FetchUsageOwnerScope(ctx, userCred, getQuery(r))
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
isOwner := false
@@ -123,7 +123,7 @@ func rangeObjHandler(
}
usage, err := reporter(scope, ownerId, isOwner, rangeObjs, hostTypes, providers, brands, cloudEnv, includeSystem)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
response(w, usage)
+1 -1
View File
@@ -156,7 +156,7 @@ func performImageCache(
disk, err := body.Get("disk")
if err != nil {
httperrors.MissingParameterError(w, "disk")
httperrors.MissingParameterError(ctx, w, "disk")
return
}
+10 -10
View File
@@ -40,7 +40,7 @@ func InitHandlers(app *appsrv.Application) {
}
var defaultHandler = func(ctx context.Context, w http.ResponseWriter, r *http.Request) {
httperrors.NotImplementedError(w, "")
httperrors.NotImplementedError(ctx, w, "")
return
}
@@ -72,7 +72,7 @@ func uploadHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
_, _, body := appsrv.FetchEnv(ctx, w, r)
disk, err := body.Get("disk")
if err != nil {
httperrors.MissingParameterError(w, "miss disk")
httperrors.MissingParameterError(ctx, w, "miss disk")
return
}
hostutils.DelayTask(ctx, esxi.EsxiAgent.AgentStorage.SaveToGlance, disk)
@@ -84,7 +84,7 @@ func deployHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
_, _, body := appsrv.FetchEnv(ctx, w, r)
disk, err := body.Get("disk")
if err != nil {
httperrors.MissingParameterError(w, "miss disk")
httperrors.MissingParameterError(ctx, w, "miss disk")
return
}
hostutils.DelayTask(ctx, esxi.EsxiAgent.AgentStorage.AgentDeployGuest, disk)
@@ -99,7 +99,7 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
if disk != nil {
_, err := disk.Delete(ctx, nil)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
hostutils.ResponseOk(ctx, w)
@@ -113,7 +113,7 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
func createHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
disk, diskInfo, err := diskAndDiskInfo(ctx, w, r)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
hostutils.DelayTask(ctx, esxi.EsxiAgent.AgentStorage.CreateDiskByDiskInfo,
@@ -125,7 +125,7 @@ func savePrepareHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
taskId := ctx.Value(appctx.APP_CONTEXT_KEY_TASK_ID).(string)
disk, diskInfo, err := diskAndDiskInfo(ctx, w, r)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
hostutils.DelayTask(ctx, disk.PrepareSaveToGlance, storageman.PrepareSaveToGlanceParams{
@@ -138,7 +138,7 @@ func savePrepareHandler(ctx context.Context, w http.ResponseWriter, r *http.Requ
func resizeHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
disk, diskInfo, err := diskAndDiskInfo(ctx, w, r)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
hostutils.DelayTask(ctx, disk.Resize, diskInfo)
@@ -151,17 +151,17 @@ func fetchHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
diskId := params["<disk_id>"]
disk := esxi.EsxiAgent.AgentStorage.GetDiskById(diskId)
if disk != nil {
httperrors.GeneralServerError(w, httperrors.NewDuplicateResourceError("disk '%s'", diskId))
httperrors.GeneralServerError(ctx, w, httperrors.NewDuplicateResourceError("disk '%s'", diskId))
return
}
disk := esxi.EsxiAgent.AgentStorage.CreateDisk(diskId)
diskInfo, err := body.Get("disk")
if err != nil {
httperrors.InputParameterError(w, "miss disk")
httperrors.InputParameterError(ctx, w, "miss disk")
}
url, err := diskInfo.GetString("url")
if err != nil {
httperrors.InputParameterError(w, "miss disk.url")
httperrors.InputParameterError(ctx, w, "miss disk.url")
}
hostutils.DelayTask(ctx, disk.CreateFromUrl)
hostutils.ResponseOk(ctx, w)
+8 -8
View File
@@ -150,7 +150,7 @@ func parseRange(reqRange string) (int64, int64, error) {
func closeImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
imagePath, err := inputCheck(ctx)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -162,7 +162,7 @@ func closeImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
}
err = f.Load(imagePath, true)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
f.Close()
@@ -172,7 +172,7 @@ func closeImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
func getImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
imagePath, err := inputCheck(ctx)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -187,7 +187,7 @@ func getImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
}
if err = f.Open(imagePath, true); err != nil {
log.Errorf("Open image error: %s", err)
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
defer f.Close()
@@ -198,7 +198,7 @@ func getImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
startPos, endPos, err = parseRange(reqRange)
if err != nil {
log.Errorf("Parse range error: %s", err)
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
}
@@ -208,7 +208,7 @@ func getImage(ctx context.Context, w http.ResponseWriter, r *http.Request) {
rateLimit, err = strconv.ParseInt(strRateLimit, 10, 0)
if err != nil {
log.Errorf("Parse ratelimit error: %s", err)
httperrors.InvalidInputError(w, "Invaild rate limit header")
httperrors.InvalidInputError(ctx, w, "Invaild rate limit header")
return
}
}
@@ -270,7 +270,7 @@ fail:
func getImageMeta(ctx context.Context, w http.ResponseWriter, r *http.Request) {
imagePath, err := inputCheck(ctx)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
@@ -281,7 +281,7 @@ func getImageMeta(ctx context.Context, w http.ResponseWriter, r *http.Request) {
f = &SQcow2Image{}
}
if err = f.Open(imagePath, true); err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
+2 -2
View File
@@ -85,7 +85,7 @@ func download(ctx context.Context, w http.ResponseWriter, r *http.Request) {
case "images":
hand := NewImageCacheDownloadProvider(w, compress, rateLimit, id)
if !fileutils2.Exists(hand.downloadFilePath()) {
httperrors.NotFoundError(w, "Image cache %s not found", id)
httperrors.NotFoundError(ctx, w, "Image cache %s not found", id)
} else {
if err := hand.Start(); err != nil {
hostutils.Response(ctx, w, err)
@@ -94,7 +94,7 @@ func download(ctx context.Context, w http.ResponseWriter, r *http.Request) {
case "servers":
hand := NewGuestDownloadProvider(w, compress, rateLimit, id)
if !fileutils2.Exists(hand.fullPath()) {
httperrors.NotFoundError(w, "Guest %s not found", id)
httperrors.NotFoundError(ctx, w, "Guest %s not found", id)
} else {
if err := hand.Start(); err != nil {
hostutils.Response(ctx, w, err)
+1 -1
View File
@@ -153,7 +153,7 @@ func Response(ctx context.Context, w http.ResponseWriter, res interface{}) {
case jsonutils.JSONObject:
appsrv.SendJSON(w, res.(jsonutils.JSONObject))
case error:
httperrors.GeneralServerError(w, res.(error))
httperrors.GeneralServerError(ctx, w, res.(error))
default:
appsrv.SendStruct(w, res)
}
@@ -93,17 +93,17 @@ func performImageCache(
disk, err := body.Get("disk")
if err != nil {
httperrors.MissingParameterError(w, "disk")
httperrors.MissingParameterError(ctx, w, "disk")
return
}
scId, err := disk.GetString("storagecache_id")
if err != nil {
httperrors.MissingParameterError(w, "disk")
httperrors.MissingParameterError(ctx, w, "disk")
return
}
storagecache := storageman.GetManager().GetStoragecacheById(scId)
if storagecache == nil {
httperrors.NotFoundError(w, "Storagecache %s not found", scId)
httperrors.NotFoundError(ctx, w, "Storagecache %s not found", scId)
return
}
+92 -53
View File
@@ -15,15 +15,43 @@
package httperrors
import (
"context"
"net/http"
"runtime/debug"
"golang.org/x/text/language"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/onecloud/pkg/util/httputils"
)
type ctxLang uintptr
const ctxLangKey = ctxLang(0)
func WithLangTag(ctx context.Context, tag language.Tag) context.Context {
return context.WithValue(ctx, ctxLangKey, tag)
}
func WithLang(ctx context.Context, lang string) context.Context {
tag, err := language.Parse(lang)
if err != nil {
tag = language.English
}
return WithLangTag(ctx, tag)
}
func WithRequestLang(ctx context.Context, req *http.Request) context.Context {
if cookie, err := req.Cookie("lang"); err == nil {
return WithLang(ctx, cookie.Value)
}
if val := req.URL.Query().Get("lang"); val != "" {
return WithLang(ctx, val)
}
return WithLangTag(ctx, language.English)
}
func SendHTTPErrorHeader(w http.ResponseWriter, statusCode int) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
@@ -33,7 +61,7 @@ func SetHTTPRedirectLocationHeader(w http.ResponseWriter, location string) {
w.Header().Set("Location", location)
}
func HTTPError(w http.ResponseWriter, msg string, statusCode int, class string, error httputils.Error) {
func HTTPError(ctx context.Context, w http.ResponseWriter, msg string, statusCode int, class string, err httputils.Error) {
if statusCode >= 300 && statusCode <= 400 {
SetHTTPRedirectLocationHeader(w, msg)
}
@@ -41,110 +69,121 @@ func HTTPError(w http.ResponseWriter, msg string, statusCode int, class string,
// 需要在调用w.WriteHeader方法之前,设置header才能生效
SendHTTPErrorHeader(w, statusCode)
var (
langv = ctx.Value(ctxLangKey)
lang language.Tag
details string
)
if langv != nil {
lang = langv.(language.Tag)
} else {
lang = language.English
}
a := make([]interface{}, len(err.Fields))
for i := range err.Fields {
a[i] = err.Fields[i]
}
details = P(lang, err.Id, a...)
body := jsonutils.NewDict()
body.Add(jsonutils.NewInt(int64(statusCode)), "code")
body.Add(jsonutils.NewString(msg), "details")
body.Add(jsonutils.NewString(class), "class")
err := jsonutils.NewDict()
err.Add(jsonutils.NewString(error.Id), "id")
err.Add(jsonutils.NewStringArray(error.Fields), "fields")
body.Add(err, "data")
body.Add(jsonutils.NewString(details), "details")
w.Write([]byte(body.String()))
log.Errorf("Send error %s", err)
log.Errorf("Send error %s", details)
if statusCode >= 500 {
debug.PrintStack()
}
}
func JsonClientError(w http.ResponseWriter, e *httputils.JSONClientError) {
HTTPError(w, e.Details, e.Code, e.Class, e.Data)
func JsonClientError(ctx context.Context, w http.ResponseWriter, e *httputils.JSONClientError) {
HTTPError(ctx, w, e.Details, e.Code, e.Class, e.Data)
}
func GeneralServerError(w http.ResponseWriter, e error) {
func GeneralServerError(ctx context.Context, w http.ResponseWriter, e error) {
je := NewGeneralError(e)
JsonClientError(w, je)
JsonClientError(ctx, w, je)
}
func BadRequestError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewBadRequestError(msg, params...))
func BadRequestError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewBadRequestError(msg, params...))
}
func PaymentError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewPaymentError(msg, params...))
func PaymentError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewPaymentError(msg, params...))
}
func UnauthorizedError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewUnauthorizedError(msg, params...))
func UnauthorizedError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewUnauthorizedError(msg, params...))
}
func InvalidCredentialError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewInvalidCredentialError(msg, params...))
func InvalidCredentialError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewInvalidCredentialError(msg, params...))
}
func ForbiddenError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewForbiddenError(msg, params...))
func ForbiddenError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewForbiddenError(msg, params...))
}
func NotFoundError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewNotFoundError(msg, params...))
func NotFoundError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewNotFoundError(msg, params...))
}
func NotImplementedError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewNotImplementedError(msg, params...))
func NotImplementedError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewNotImplementedError(msg, params...))
}
func NotAcceptableError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewNotAcceptableError(msg, params...))
func NotAcceptableError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewNotAcceptableError(msg, params...))
}
func InvalidInputError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewInputParameterError(msg, params...))
func InvalidInputError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewInputParameterError(msg, params...))
}
func InputParameterError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewInputParameterError(msg, params...))
func InputParameterError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewInputParameterError(msg, params...))
}
func MissingParameterError(w http.ResponseWriter, param string) {
JsonClientError(w, NewMissingParameterError(param))
func MissingParameterError(ctx context.Context, w http.ResponseWriter, param string) {
JsonClientError(ctx, w, NewMissingParameterError(param))
}
func ConflictError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewConflictError(msg, params...))
func ConflictError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewConflictError(msg, params...))
}
func InternalServerError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewInternalServerError(msg, params...))
func InternalServerError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewInternalServerError(msg, params...))
}
func BadGatewayError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewBadGatewayError(msg, params...))
func BadGatewayError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewBadGatewayError(msg, params...))
}
func TenantNotFoundError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewTenantNotFoundError(msg, params...))
func TenantNotFoundError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewTenantNotFoundError(msg, params...))
}
func OutOfQuotaError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewOutOfQuotaError(msg, params...))
func OutOfQuotaError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewOutOfQuotaError(msg, params...))
}
func NotSufficientPrivilegeError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewNotSufficientPrivilegeError(msg, params...))
func NotSufficientPrivilegeError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewNotSufficientPrivilegeError(msg, params...))
}
func ResourceNotFoundError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewResourceNotFoundError(msg, params...))
func ResourceNotFoundError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewResourceNotFoundError(msg, params...))
}
func TimeoutError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewTimeoutError(msg, params...))
func TimeoutError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewTimeoutError(msg, params...))
}
func ProtectedResourceError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewProtectedResourceError(msg, params...))
func ProtectedResourceError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewProtectedResourceError(msg, params...))
}
func NoProjectError(w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(w, NewNoProjectError(msg, params...))
func NoProjectError(ctx context.Context, w http.ResponseWriter, msg string, params ...interface{}) {
JsonClientError(ctx, w, NewNoProjectError(msg, params...))
}
+13
View File
@@ -0,0 +1,13 @@
package httperrors
import (
"golang.org/x/text/language"
"golang.org/x/text/message"
"yunion.io/x/onecloud/locales"
)
func P(tag language.Tag, id string, a ...interface{}) string {
p := message.NewPrinter(tag, message.Catalog(locales.Catalog))
return p.Sprintf(id, a...)
}
+1 -1
View File
@@ -41,7 +41,7 @@ func ReportGeneralUsage(ctx context.Context, w http.ResponseWriter, r *http.Requ
ownerId, scope, err := db.FetchUsageOwnerScope(ctx, userCred, query)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
+1 -1
View File
@@ -445,7 +445,7 @@ func roleAssignmentHandler(ctx context.Context, w http.ResponseWriter, r *http.R
results, total, err := AssignmentManager.FetchAll(userId, groupId, roleId, domainId, projectId, includeNames, effective, includeSub, includeSystem, includePolicies, int(limit), int(offset))
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
body := jsonutils.NewDict()
+2 -2
View File
@@ -511,7 +511,7 @@ func (project *SProject) PerformJoin(
) (jsonutils.JSONObject, error) {
err := input.Validate()
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
roleNames := make([]string, 0)
@@ -597,7 +597,7 @@ func (project *SProject) PerformLeave(
) (jsonutils.JSONObject, error) {
err := input.Validate()
if err != nil {
return nil, httperrors.NewInputParameterError(err.Error())
return nil, httperrors.NewInputParameterError("%v", err)
}
for i := range input.UserRoles {
+1 -1
View File
@@ -951,7 +951,7 @@ func (user *SUser) PerformJoin(
func joinProjects(ident db.IModel, isUser bool, ctx context.Context, userCred mcclient.TokenCredential, input api.SJoinProjectsInput) error {
err := input.Validate()
if err != nil {
return httperrors.NewInputParameterError(err.Error())
return httperrors.NewInputParameterError("%v", err)
}
projects := make([]*SProject, 0)
+19 -19
View File
@@ -55,13 +55,13 @@ func authenticateTokensV2(ctx context.Context, w http.ResponseWriter, r *http.Re
input := mcclient.SAuthenticationInputV2{}
err := body.Unmarshal(&input)
if err != nil {
httperrors.InvalidInputError(w, "unrecognized input %s", err)
httperrors.InvalidInputError(ctx, w, "unrecognized input %s", err)
return
}
input.Auth.Context = FetchAuthContext(input.Auth.Context, r)
token, err := AuthenticateV2(ctx, input)
if token == nil {
httperrors.UnauthorizedError(w, "unauthorized %s", err)
httperrors.UnauthorizedError(ctx, w, "unauthorized %s", err)
return
}
appsrv.SendJSON(w, jsonutils.Marshal(token))
@@ -72,13 +72,13 @@ func authenticateTokensV2(ctx context.Context, w http.ResponseWriter, r *http.Re
func authenticateTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Request) {
_, _, body := appsrv.FetchEnv(ctx, w, r)
if body == nil {
httperrors.InvalidInputError(w, "fail to decode request body")
httperrors.InvalidInputError(ctx, w, "fail to decode request body")
return
}
input := mcclient.SAuthenticationInputV3{}
err := body.Unmarshal(&input)
if err != nil {
httperrors.InvalidInputError(w, "unrecognized input %s", err)
httperrors.InvalidInputError(ctx, w, "unrecognized input %s", err)
return
}
input.Auth.Context = FetchAuthContext(input.Auth.Context, r)
@@ -86,16 +86,16 @@ func authenticateTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Re
if err != nil {
switch errors.Cause(err) {
case sqlchemy.ErrDuplicateEntry:
httperrors.ConflictError(w, "duplicate username")
httperrors.ConflictError(ctx, w, "duplicate username")
case httperrors.ErrTooManyAttempts, httperrors.ErrUserNotFound:
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
default:
httperrors.UnauthorizedError(w, "unauthorized %s", err)
httperrors.UnauthorizedError(ctx, w, "unauthorized %s", err)
}
return
}
if token == nil {
httperrors.UnauthorizedError(w, "user not found or not enabled")
httperrors.UnauthorizedError(ctx, w, "user not found or not enabled")
return
}
w.Header().Set(api.AUTH_SUBJECT_TOKEN_HEADER, token.Id)
@@ -126,27 +126,27 @@ func verifyTokensV2(ctx context.Context, w http.ResponseWriter, r *http.Request)
tokenStr := params["<token>"]
token, err := verifyCommon(ctx, w, tokenStr)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
user, err := models.UserManager.FetchUserExtended(token.UserId, "", "", "")
if err != nil {
httperrors.InvalidCredentialError(w, "invalid user")
httperrors.InvalidCredentialError(ctx, w, "invalid user")
return
}
project, err := models.ProjectManager.FetchProject(token.ProjectId, "", "", "")
if err != nil {
httperrors.InvalidCredentialError(w, "invalid project")
httperrors.InvalidCredentialError(ctx, w, "invalid project")
return
}
projExt, err := project.FetchExtend()
if err != nil {
httperrors.InvalidCredentialError(w, "invalid project")
httperrors.InvalidCredentialError(ctx, w, "invalid project")
return
}
v2token, err := token.getTokenV2(ctx, user, projExt)
if err != nil {
httperrors.InternalServerError(w, "internal server error %s", err)
httperrors.InternalServerError(ctx, w, "internal server error %s", err)
return
}
ret := jsonutils.NewDict()
@@ -174,13 +174,13 @@ func verifyTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Request)
tokenStr := r.Header.Get(api.AUTH_SUBJECT_TOKEN_HEADER)
token, err := verifyCommon(ctx, w, tokenStr)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
user, err := models.UserManager.FetchUserExtended(token.UserId, "", "", "")
if err != nil {
httperrors.InvalidCredentialError(w, "invalid user")
httperrors.InvalidCredentialError(ctx, w, "invalid user")
return
}
var projExt *models.SProjectExtended
@@ -188,25 +188,25 @@ func verifyTokensV3(ctx context.Context, w http.ResponseWriter, r *http.Request)
if len(token.ProjectId) > 0 {
project, err := models.ProjectManager.FetchProject(token.ProjectId, "", "", "")
if err != nil {
httperrors.InvalidCredentialError(w, "invalid project")
httperrors.InvalidCredentialError(ctx, w, "invalid project")
return
}
projExt, err = project.FetchExtend()
if err != nil {
httperrors.InvalidCredentialError(w, "invalid project")
httperrors.InvalidCredentialError(ctx, w, "invalid project")
return
}
} else if len(token.DomainId) > 0 {
domain, err = models.DomainManager.FetchDomainById(token.DomainId)
if err != nil {
httperrors.InvalidCredentialError(w, "invalid domain")
httperrors.InvalidCredentialError(ctx, w, "invalid domain")
return
}
}
v3token, err := token.getTokenV3(ctx, user, projExt, domain, api.SAccessKeySecretInfo{})
if err != nil {
httperrors.InternalServerError(w, "internal server error %s", err)
httperrors.InternalServerError(ctx, w, "internal server error %s", err)
return
}
w.Header().Set(api.AUTH_SUBJECT_TOKEN_HEADER, v3token.Id)
+1 -1
View File
@@ -74,7 +74,7 @@ func ReportGeneralUsage(ctx context.Context, w http.ResponseWriter, r *http.Requ
// if !isAdmin && !isProject {
if !isAdmin {
httperrors.ForbiddenError(w, "not allow to get usage")
httperrors.ForbiddenError(ctx, w, "not allow to get usage")
return
}
+2 -2
View File
@@ -52,7 +52,7 @@ func AuthenticateWithDelayDecision(f appsrv.FilterHandler, delayDecision bool) a
if len(tokenStr) == 0 {
log.Errorf("no auth_token found! delayDecision=%v", delayDecision)
if !delayDecision {
httperrors.UnauthorizedError(w, "Unauthorized")
httperrors.UnauthorizedError(ctx, w, "Unauthorized")
return
}
token = &GuestToken
@@ -62,7 +62,7 @@ func AuthenticateWithDelayDecision(f appsrv.FilterHandler, delayDecision bool) a
if err != nil {
log.Errorf("Verify token failed: %s", err)
if !delayDecision {
httperrors.UnauthorizedError(w, "InvalidToken")
httperrors.UnauthorizedError(ctx, w, "InvalidToken")
return
}
}
+3 -7
View File
@@ -88,8 +88,7 @@ func (this *HostManager) GetIpmiInfo(s *mcclient.ClientSession, id string, param
return ret, nil
}
func parseHosts(titles []string, data string) ([]*jsonutils.JSONDict, string) {
msg := ""
func parseHosts(titles []string, data string) []*jsonutils.JSONDict {
hosts := strings.Split(data, "\n")
ret := []*jsonutils.JSONDict{}
for i, host := range hosts {
@@ -114,7 +113,7 @@ func parseHosts(titles []string, data string) ([]*jsonutils.JSONDict, string) {
ret = append(ret, params)
}
return ret, msg
return ret
}
func (this *HostManager) BatchRegister(s *mcclient.ClientSession, titles []string, params jsonutils.JSONObject) ([]modulebase.SubmitResult, error) {
@@ -125,10 +124,7 @@ func (this *HostManager) BatchRegister(s *mcclient.ClientSession, titles []strin
input := params.(*jsonutils.JSONDict)
input.Remove("hosts")
hosts, msg := parseHosts(titles, data)
if len(msg) > 0 {
return nil, httperrors.NewInputParameterError(msg)
}
hosts := parseHosts(titles, data)
results := make(chan modulebase.SubmitResult, len(hosts))
for _, host := range hosts {
+6 -6
View File
@@ -42,7 +42,7 @@ func emailConfigDeleteHandler(ctx context.Context, w http.ResponseWriter, r *htt
}
err := manager.DeleteConfig(ctx, params)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
}
@@ -53,7 +53,7 @@ func emailConfigGetHandler(ctx context.Context, w http.ResponseWriter, r *http.R
}
ret, err := manager.GetConfig(ctx, params, query)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
data, _ := ret.Get("config")
dataDict := data.(*jsonutils.JSONDict)
@@ -70,7 +70,7 @@ func emailConfigUpdateHandler(ctx context.Context, w http.ResponseWriter, r *htt
newBody.Add(body, EMAIL)
err := manager.UpdateConfig(ctx, newBody)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
data := jsonutils.NewDict()
data.Add(jsonutils.NewInt(200), "code")
@@ -89,7 +89,7 @@ func smsConfigDeleteHandler(ctx context.Context, w http.ResponseWriter, r *http.
}
err := manager.DeleteConfig(ctx, params)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
}
@@ -100,7 +100,7 @@ func smsConfigGetHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
}
ret, err := manager.GetConfig(ctx, params, query)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
// modify
data, _ := ret.Get("config")
@@ -116,7 +116,7 @@ func smsConfigUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.
newBody.Add(body, SMS)
err := manager.UpdateConfig(ctx, newBody)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
data := jsonutils.NewDict()
data.Add(jsonutils.NewInt(200), "code")
+9 -7
View File
@@ -545,21 +545,23 @@ func (self *NotifyModelDispatcher) UpdateContacts(ctx context.Context, idstr str
// keep the return value same as this of the GET interface
ret := jsonutils.NewDict()
contact, err := models.ContactManager.FetchByUIDs(ctx, []string{idstr}, false)
contacts, err := models.ContactManager.FetchByUIDs(ctx, []string{idstr}, false)
if err != nil {
log.Errorf(err.Error())
log.Errorf("fetch contact %s: %v", idstr, err)
return ret, nil
}
if len(contact) == 0 {
if len(contacts) == 0 {
return nil, nil
}
outDetails, err := contact[0].GetExtraDetails(ctx, userCred, ret, false)
contact := contacts[0]
outDetails, err := contact.GetExtraDetails(ctx, userCred, ret, false)
if err != nil {
log.Errorf(err.Error())
log.Errorf("fetch contact details %s(%s): %v",
contact.GetName(), contact.GetId(), err)
return ret, nil
}
out := jsonutils.Marshal(outDetails)
out.(*jsonutils.JSONDict).Set("created_at", jsonutils.NewString(contact[0].CreatedAt.String()))
out.(*jsonutils.JSONDict).Set("created_at", jsonutils.NewString(contact.CreatedAt.String()))
return out, nil
}
@@ -684,7 +686,7 @@ func DeleteItem(model db.IModel, ctx context.Context, userCred mcclient.TokenCre
err = db.CustomizeDelete(model, ctx, userCred, query, data)
if err != nil {
log.Errorf("customize delete error: %s", err)
return httperrors.NewNotAcceptableError(err.Error())
return httperrors.NewNotAcceptableError("%v", err)
}
model.PreDelete(ctx, userCred)
err = model.Delete(ctx, userCred)
+26 -26
View File
@@ -65,7 +65,7 @@ func middleware(f appsrv.FilterHandler) appsrv.FilterHandler {
if uid, ok := params["<uid>"]; ok {
userDetail, err := utils.GetUserByIDOrName(ctx, uid)
if err != nil {
httperrors.NotFoundError(w, "Uid or Uname Not Found")
httperrors.NotFoundError(ctx, w, "Uid or Uname Not Found")
return
}
log.Debugf("find userDetail, id: %s, name: %s", userDetail.Id, userDetail.Name)
@@ -197,31 +197,31 @@ func templateUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.R
manager, params, query, body := fetchEnv(ctx, w, r)
data, err := body.GetArray(manager.Keyword(), manager.KeywordPlural())
if err != nil {
httperrors.GeneralServerError(w, httperrors.NewInputParameterError("need %s and %s",
httperrors.GeneralServerError(ctx, w, httperrors.NewInputParameterError("need %s and %s",
manager.Keyword(), manager.KeywordPlural()))
return
}
ctype := params["<ctype>"]
if len(ctype) == 0 {
httperrors.InputParameterError(w, "ctype of template should not be empty")
httperrors.InputParameterError(ctx, w, "ctype of template should not be empty")
}
err = manager.UpdateTemplate(ctx, ctype, mergeQueryParams(params, query), data)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
}
func deleteTemplateHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
manager, _, query, body := fetchEnv(ctx, w, r)
if !body.Contains("contact_type") {
httperrors.InputParameterError(w, "miss contact_type")
httperrors.InputParameterError(ctx, w, "miss contact_type")
return
}
ctype, _ := body.GetString("contact_type")
topic, _ := body.GetString("topic")
err := manager.DeleteTemplate(ctx, query, ctype, topic)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
}
@@ -229,7 +229,7 @@ func configDeleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
manager, params, _, _ := fetchEnv(ctx, w, r)
err := manager.DeleteConfig(ctx, params)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
}
@@ -237,7 +237,7 @@ func configGetHandler(ctx context.Context, w http.ResponseWriter, r *http.Reques
manager, params, query, _ := fetchEnv(ctx, w, r)
ret, err := manager.GetConfig(ctx, params, query)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, ret)
@@ -247,12 +247,12 @@ func configUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
manager, _, _, body := fetchEnv(ctx, w, r)
body, err := body.Get(models.ConfigManager.Keyword())
if err != nil {
httperrors.GeneralServerError(w, httperrors.NewInputParameterError("need config or configs"))
httperrors.GeneralServerError(ctx, w, httperrors.NewInputParameterError("need config or configs"))
return
}
err = manager.UpdateConfig(ctx, body)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
}
@@ -260,12 +260,12 @@ func configValidateHandler(ctx context.Context, w http.ResponseWriter, r *http.R
manager, params, _, body := fetchEnv(ctx, w, r)
body, err := body.Get(models.ConfigManager.Keyword())
if err != nil {
httperrors.GeneralServerError(w, httperrors.NewInputParameterError("need config"))
httperrors.GeneralServerError(ctx, w, httperrors.NewInputParameterError("need config"))
}
ctype := params["<type>"]
err = manager.ValidateConfig(ctx, ctype, body)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
}
@@ -274,16 +274,16 @@ func notificationHandler(ctx context.Context, w http.ResponseWriter, r *http.Req
manager, _, _, body := fetchEnv(ctx, w, r)
data, err := body.Get(manager.Keyword())
if err != nil {
httperrors.BadRequestError(w, "request body should contain %s", manager.Keyword())
httperrors.BadRequestError(ctx, w, "request body should contain %s", manager.Keyword())
return
}
if !data.Contains("gid") && !data.Contains("uid") {
httperrors.MissingParameterError(w, "gid | uid")
httperrors.MissingParameterError(ctx, w, "gid | uid")
return
}
_, err = manager.CreateNotification(ctx, data)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
}
@@ -293,7 +293,7 @@ func verifyHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
manager, params, query, _ := fetchEnv(ctx, w, r)
err := manager.Verify(ctx, params, query)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
}
}
@@ -305,7 +305,7 @@ func contactUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
data, err := body.GetArray(manager.Keyword(), manager.KeywordPlural())
if err != nil {
log.Errorf("body: %s, err: %s\n", body.String(), err)
httperrors.GeneralServerError(w, httperrors.NewInputParameterError("need %s and %s",
httperrors.GeneralServerError(ctx, w, httperrors.NewInputParameterError("need %s and %s",
manager.Keyword(), manager.KeywordPlural()))
return
}
@@ -317,7 +317,7 @@ func contactUpdateHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
out, err := manager.UpdateContacts(ctx, uid, mergeQueryParams(params, query), data, pullCtypes, nil)
if err != nil {
log.Errorf(err.Error())
httperrors.BadRequestError(w, "")
httperrors.BadRequestError(ctx, w, "")
return
}
if out == nil {
@@ -335,7 +335,7 @@ func deleteContactHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
if body != nil {
data, err = body.GetArray(manager.KeywordPlural())
if err != nil {
httperrors.BadRequestError(w, "request body should have %s", manager.KeywordPlural())
httperrors.BadRequestError(ctx, w, "request body should have %s", manager.KeywordPlural())
return
}
}
@@ -343,7 +343,7 @@ func deleteContactHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
if err != nil {
log.Errorf("delete contact of %s failed, error: %s", data, err)
httperrors.GeneralServerError(w, errors.Error("delete failed"))
httperrors.GeneralServerError(ctx, w, errors.Error("delete failed"))
}
}
@@ -352,13 +352,13 @@ func verifyTriggerHandler(ctx context.Context, w http.ResponseWriter, r *http.Re
manager, params, _, body := fetchEnv(ctx, w, r)
data, err := body.Get(models.ContactManager.Keyword())
if err != nil {
httperrors.BadRequestError(w, "request body should have %s", manager.Keyword())
httperrors.BadRequestError(ctx, w, "request body should have %s", manager.Keyword())
return
}
ret, err := manager.VerifyTrigger(ctx, params, data)
if err != nil {
log.Errorf("verifyTrigger failed beacause %s", err)
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, ret)
@@ -369,7 +369,7 @@ func listHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
manager, params, query, _ := fetchEnv(ctx, w, r)
listResult, err := manager.List(ctx, mergeQueryParams(params, query), nil)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendJSON(w, modulebase.ListResult2JSONWithKey(listResult, manager.KeywordPlural()))
@@ -379,7 +379,7 @@ func getHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
manager, params, query, _ := fetchEnv(ctx, w, r)
listResult, err := manager.List(ctx, mergeQueryParams(params, query), nil)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
var data jsonutils.JSONObject
@@ -407,14 +407,14 @@ func keyStoneUserListHandler(ctx context.Context, w http.ResponseWriter, r *http
users, err := modules.UsersV3.List(s, query)
if err != nil {
log.Errorf("keystone list error: %s", err)
httperrors.InternalServerError(w, err.Error())
httperrors.InternalServerError(ctx, w, err.Error())
return
}
q := models.ContactManager.Query("uid").GroupBy("uid")
row, err := q.Rows()
if err != nil {
log.Errorf("get contact's uid error: %s", err)
httperrors.InternalServerError(w, err.Error())
httperrors.InternalServerError(ctx, w, err.Error())
return
}
defer row.Close()
+3 -3
View File
@@ -56,12 +56,12 @@ func NewHTTPReverseProxy(ef *SEndpointFactory, m RequestManipulator) *SReversePr
func (p *SReverseProxy) ServeHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request) {
endpoint, err := p.generator(ctx, r)
if err != nil {
httperrors.InternalServerError(w, err.Error())
httperrors.InternalServerError(httperrors.WithRequestLang(ctx, r), w, "%v", err)
return
}
remoteUrl, err := url.Parse(endpoint)
if err != nil {
httperrors.InternalServerError(w, "failed parsing url %q: %v", endpoint, err)
httperrors.InternalServerError(httperrors.WithRequestLang(ctx, r), w, "failed parsing url %q: %v", endpoint, err)
return
}
log.Debugf("Forwarding to servie: %q, url: %q", p.serviceName, remoteUrl.String())
@@ -73,7 +73,7 @@ func (p *SReverseProxy) ServeHTTP(ctx context.Context, w http.ResponseWriter, r
}
r, err = p.manipulator(ctx, r)
if err != nil {
httperrors.InternalServerError(w, err.Error())
httperrors.InternalServerError(httperrors.WithRequestLang(ctx, r), w, "%v", err)
return
}
proxy.ServeHTTP(w, r)
+4 -4
View File
@@ -92,9 +92,9 @@ func OutOfRangeError(ctx context.Context, msg string) s3cli.ErrorResponse {
func SendGeneralError(ctx context.Context, w http.ResponseWriter, err error) {
switch e := err.(type) {
case s3cli.ErrorResponse:
SendError(w, e)
SendError(ctx, w, e)
case *s3cli.ErrorResponse:
SendError(w, *e)
SendError(ctx, w, *e)
default:
var eresp s3cli.ErrorResponse
cause := errors.Cause(err)
@@ -124,11 +124,11 @@ func SendGeneralError(ctx context.Context, w http.ResponseWriter, err error) {
default:
eresp = ServerError(ctx, err.Error())
}
SendError(w, eresp)
SendError(ctx, w, eresp)
}
}
func SendError(w http.ResponseWriter, resp s3cli.ErrorResponse) {
func SendError(ctx context.Context, w http.ResponseWriter, resp s3cli.ErrorResponse) {
w.WriteHeader(resp.StatusCode)
log.Errorf("SendError: %s", resp)
+13 -13
View File
@@ -144,7 +144,7 @@ func headHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
} else {
// do nothing
}
SendError(w, NotSupported(ctx, "method not supported"))
SendError(ctx, w, NotSupported(ctx, "method not supported"))
}
func readBucket(ctx context.Context, userCred mcclient.TokenCredential, bucketName string, query jsonutils.JSONObject, r *http.Request) (interface{}, http.Header, error) {
@@ -302,13 +302,13 @@ func readHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// service
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
SendError(w, BadRequest(ctx, err.Error()))
SendError(ctx, w, BadRequest(ctx, err.Error()))
return
}
input := s3cli.ListBucketsInput{}
err = query.Unmarshal(&input)
if err != nil {
SendError(w, BadRequest(ctx, err.Error()))
SendError(ctx, w, BadRequest(ctx, err.Error()))
} else {
resp, err := listService(ctx, userCred, input)
if err != nil {
@@ -321,7 +321,7 @@ func readHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// bucket get
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
SendError(w, BadRequest(ctx, err.Error()))
SendError(ctx, w, BadRequest(ctx, err.Error()))
return
}
resp, respHdr, err := readBucket(ctx, userCred, o.Bucket, query, r)
@@ -342,7 +342,7 @@ func readHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
}
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
SendError(w, BadRequest(ctx, err.Error()))
SendError(ctx, w, BadRequest(ctx, err.Error()))
return
}
resp, respHdr, err := readObject(ctx, userCred, o.Bucket, o.Key, query, r)
@@ -394,7 +394,7 @@ func postHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// object post
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
SendError(w, BadRequest(ctx, err.Error()))
SendError(ctx, w, BadRequest(ctx, err.Error()))
return
}
resp, respHdr, err := postObject(ctx, userCred, o.Bucket, o.Key, query, r)
@@ -405,7 +405,7 @@ func postHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
appsrv.SendXml(w, respHdr, resp)
return
}
SendError(w, NotSupported(ctx, "method not supported"))
SendError(ctx, w, NotSupported(ctx, "method not supported"))
}
func putBucket(ctx context.Context, userCred mcclient.TokenCredential, bucket string, query jsonutils.JSONObject, r *http.Request) (interface{}, http.Header, error) {
@@ -489,7 +489,7 @@ func putHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// bucket put
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
SendError(w, BadRequest(ctx, err.Error()))
SendError(ctx, w, BadRequest(ctx, err.Error()))
return
}
resp, respHdr, err := putBucket(ctx, userCred, o.Bucket, query, r)
@@ -503,7 +503,7 @@ func putHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
// object put
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
SendError(w, BadRequest(ctx, err.Error()))
SendError(ctx, w, BadRequest(ctx, err.Error()))
return
}
resp, respHdr, err := putObject(ctx, userCred, o.Bucket, o.Key, query, r)
@@ -514,7 +514,7 @@ func putHandler(ctx context.Context, w http.ResponseWriter, r *http.Request) {
appsrv.SendXml(w, respHdr, resp)
return
}
SendError(w, NotSupported(ctx, "method not supported"))
SendError(ctx, w, NotSupported(ctx, "method not supported"))
}
func deleteBucket(ctx context.Context, userCred mcclient.TokenCredential, bucket string, query jsonutils.JSONObject) (interface{}, error) {
@@ -573,7 +573,7 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
// bucket delete
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
SendError(w, BadRequest(ctx, err.Error()))
SendError(ctx, w, BadRequest(ctx, err.Error()))
return
}
resp, err := deleteBucket(ctx, userCred, o.Bucket, query)
@@ -587,7 +587,7 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
// object delete
query, err := jsonutils.ParseQueryString(r.URL.RawQuery)
if err != nil {
SendError(w, BadRequest(ctx, err.Error()))
SendError(ctx, w, BadRequest(ctx, err.Error()))
return
}
resp, err := deleteObject(ctx, userCred, o.Bucket, o.Key, query)
@@ -598,5 +598,5 @@ func deleteHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)
}
return
}
SendError(w, NotSupported(ctx, "method not supported"))
SendError(ctx, w, NotSupported(ctx, "method not supported"))
}
+2 -2
View File
@@ -36,13 +36,13 @@ func s3authenticate(f appsrv.FilterHandler) appsrv.FilterHandler {
o, err := getObjectRequest(r)
if err != nil {
SendError(w, BadRequest(ctx, err.Error()))
SendError(ctx, w, BadRequest(ctx, err.Error()))
return
}
ctx = context.WithValue(ctx, S3_OBJECT_REQUEST, o)
userCred, err := auth.VerifyRequest(*r, o.VirtualHost)
if err != nil {
SendError(w, Unauthenticated(ctx, err.Error()))
SendError(ctx, w, Unauthenticated(ctx, err.Error()))
return
}
ctx = context.WithValue(ctx, appctx.APP_CONTEXT_KEY_AUTH_TOKEN, userCred)
+1 -1
View File
@@ -36,7 +36,7 @@ func errorMessage(msgFmt string, params ...interface{}) (string, Error) {
}
err := Error{
Id: msgFmtToTmpl(msgFmt),
Id: msgFmt,
Fields: fields,
}
+4 -4
View File
@@ -151,13 +151,13 @@ func (idp *SSAMLIdpInstance) redirectLoginHandler(ctx context.Context, w http.Re
input := samlutils.SIdpRedirectLoginInput{}
err := query.Unmarshal(&input)
if err != nil {
httperrors.InputParameterError(w, "query.Unmarshal error %s", err)
httperrors.InputParameterError(ctx, w, "query.Unmarshal error %s", err)
return
}
log.Debugf("recv input %s", input)
respHtml, err := idp.processLoginRequest(ctx, idpId, input)
if err != nil {
httperrors.InputParameterError(w, "parse parameter error %s", err)
httperrors.InputParameterError(ctx, w, "parse parameter error %s", err)
return
}
appsrv.SendHTML(w, respHtml)
@@ -176,12 +176,12 @@ func (idp *SSAMLIdpInstance) idpInitiatedSSOHandler(ctx context.Context, w http.
input := samlutils.SIdpInitiatedLoginInput{}
err := query.Unmarshal(&input)
if err != nil {
httperrors.InputParameterError(w, "unmarshal input fail %s", err)
httperrors.InputParameterError(ctx, w, "unmarshal input fail %s", err)
return
}
respHtml, err := idp.processIdpInitiatedLogin(ctx, input)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendHTML(w, respHtml)
+3 -3
View File
@@ -163,7 +163,7 @@ func (sp *SSAMLSpInstance) assertionConsumeHandler(ctx context.Context, w http.R
err := sp.processAssertionConsumer(ctx, w, samlResponse, relayState)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
}
@@ -173,12 +173,12 @@ func (sp *SSAMLSpInstance) spInitiatedSSOHandler(ctx context.Context, w http.Res
input := samlutils.SSpInitiatedLoginInput{}
err := query.Unmarshal(&input)
if err != nil {
httperrors.InputParameterError(w, "unmarshal input fail %s", err)
httperrors.InputParameterError(ctx, w, "unmarshal input fail %s", err)
return
}
redirectUrl, err := sp.ProcessSpInitiatedLogin(ctx, input)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
appsrv.SendRedirect(w, redirectUrl)
+22 -22
View File
@@ -134,12 +134,12 @@ func handleK8sCommand(
) {
env, err := fetchK8sEnv(ctx, w, r)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
cmd := cmdFactory(env)
handleCommandSession(cmd, w)
handleCommandSession(ctx, cmd, w)
}
func handleK8sShell(ctx context.Context, w http.ResponseWriter, r *http.Request) {
@@ -154,86 +154,86 @@ func handleSshShell(ctx context.Context, w http.ResponseWriter, r *http.Request)
userCred := auth.FetchUserCredential(ctx, policy.FilterPolicyCredential)
env, err := fetchCloudEnv(ctx, w, r)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
cmd, err := command.NewSSHtoolSolCommand(ctx, userCred, env.Params["<ip>"], env.Body)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
handleCommandSession(cmd, w)
handleCommandSession(ctx, cmd, w)
}
func handleBaremetalShell(ctx context.Context, w http.ResponseWriter, r *http.Request) {
env, err := fetchCloudEnv(ctx, w, r)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
hostId := env.Params["<id>"]
ret, err := modules.Hosts.GetSpecific(env.ClientSessin, hostId, "ipmi", nil)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
info := command.IpmiInfo{}
err = ret.Unmarshal(&info)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
cmd, err := command.NewIpmitoolSolCommand(&info)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
handleCommandSession(cmd, w)
handleCommandSession(ctx, cmd, w)
}
func handleServerRemoteConsole(ctx context.Context, w http.ResponseWriter, r *http.Request) {
env, err := fetchCloudEnv(ctx, w, r)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
srvId := env.Params["<id>"]
info, err := session.NewRemoteConsoleInfoByCloud(env.ClientSessin, srvId)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
switch info.Protocol {
case session.ALIYUN, session.QCLOUD, session.OPENSTACK, session.VMRC, session.ZSTACK, session.CTYUN:
responsePublicCloudConsole(info, w)
responsePublicCloudConsole(ctx, info, w)
case session.VNC, session.SPICE, session.WMKS:
handleDataSession(info, w, url.Values{"password": {info.GetPassword()}}, true)
handleDataSession(ctx, info, w, url.Values{"password": {info.GetPassword()}}, true)
default:
httperrors.NotAcceptableError(w, "Unspported remote console protocol: %s", info.Protocol)
httperrors.NotAcceptableError(ctx, w, "Unspported remote console protocol: %s", info.Protocol)
}
}
func responsePublicCloudConsole(info *session.RemoteConsoleInfo, w http.ResponseWriter) {
func responsePublicCloudConsole(ctx context.Context, info *session.RemoteConsoleInfo, w http.ResponseWriter) {
data := jsonutils.NewDict()
params, err := info.GetConnectParams()
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
data.Add(jsonutils.NewString(params), "connect_params")
sendJSON(w, data)
}
func handleDataSession(sData session.ISessionData, w http.ResponseWriter, connParams url.Values, b64Encode bool) {
func handleDataSession(ctx context.Context, sData session.ISessionData, w http.ResponseWriter, connParams url.Values, b64Encode bool) {
s, err := session.Manager.Save(sData)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
data := jsonutils.NewDict()
params, err := s.GetConnectParams(connParams)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
if b64Encode {
@@ -244,8 +244,8 @@ func handleDataSession(sData session.ISessionData, w http.ResponseWriter, connPa
sendJSON(w, data)
}
func handleCommandSession(cmd command.ICommand, w http.ResponseWriter) {
handleDataSession(session.WrapCommandSession(cmd), w, nil, false)
func handleCommandSession(ctx context.Context, cmd command.ICommand, w http.ResponseWriter) {
handleDataSession(ctx, session.WrapCommandSession(cmd), w, nil, false)
}
func sendJSON(w http.ResponseWriter, body jsonutils.JSONObject) {
+7 -4
View File
@@ -15,6 +15,7 @@
package server
import (
"context"
"net/http"
"yunion.io/x/jsonutils"
@@ -32,20 +33,22 @@ func NewConnectionServer() *ConnectionServer {
}
func (s *ConnectionServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
ctx := context.Background()
ctx = httperrors.WithRequestLang(ctx, req)
query, err := jsonutils.ParseQueryString(req.URL.RawQuery)
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
log.Debugf("[connection] Get query: %v", query)
accessToken, _ := query.GetString("access_token")
if accessToken == "" {
httperrors.BadRequestError(w, "Empty access_token")
httperrors.BadRequestError(ctx, w, "Empty access_token")
return
}
sessionObj, ok := session.Manager.Get(accessToken)
if !ok {
httperrors.NotFoundError(w, "session not found")
httperrors.NotFoundError(ctx, w, "session not found")
return
}
var srv http.Handler
@@ -59,7 +62,7 @@ func (s *ConnectionServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
srv, err = NewTTYServer(sessionObj)
}
if err != nil {
httperrors.GeneralServerError(w, err)
httperrors.GeneralServerError(ctx, w, err)
return
}
srv.ServeHTTP(w, req)
+70
View File
@@ -0,0 +1,70 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package plural
// Form defines a plural form.
//
// Not all languages support all forms. Also, the meaning of each form varies
// per language. It is important to note that the name of a form does not
// necessarily correspond one-to-one with the set of numbers. For instance,
// for Croation, One matches not only 1, but also 11, 21, etc.
//
// Each language must at least support the form "other".
type Form byte
const (
Other Form = iota
Zero
One
Two
Few
Many
)
var countMap = map[string]Form{
"other": Other,
"zero": Zero,
"one": One,
"two": Two,
"few": Few,
"many": Many,
}
type pluralCheck struct {
// category:
// 3..7: opID
// 0..2: category
cat byte
setID byte
}
// opID identifies the type of operand in the plural rule, being i, n or f.
// (v, w, and t are treated as filters in our implementation.)
type opID byte
const (
opMod opID = 0x1 // is '%' used?
opNotEqual opID = 0x2 // using "!=" to compare
opI opID = 0 << 2 // integers after taking the absolute value
opN opID = 1 << 2 // full number (must be integer)
opF opID = 2 << 2 // fraction
opV opID = 3 << 2 // number of visible digits
opW opID = 4 << 2 // number of visible digits without trailing zeros
opBretonM opID = 5 << 2 // hard-wired rule for Breton
opItalian800 opID = 6 << 2 // hard-wired rule for Italian
opAzerbaijan00s opID = 7 << 2 // hard-wired rule for Azerbaijan
)
const (
// Use this plural form to indicate the next rule needs to match as well.
// The last condition in the list will have the correct plural form.
andNext = 0x7
formMask = 0x7
opShift = 3
// numN indicates the maximum integer, or maximum mod value, for which we
// have inclusion masks.
numN = 100
// The common denominator of the modulo that is taken.
maxMod = 100
)
+244
View File
@@ -0,0 +1,244 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package plural
import (
"fmt"
"io/ioutil"
"reflect"
"strconv"
"golang.org/x/text/internal/catmsg"
"golang.org/x/text/internal/number"
"golang.org/x/text/language"
"golang.org/x/text/message/catalog"
)
// TODO: consider deleting this interface. Maybe VisibleDigits is always
// sufficient and practical.
// Interface is used for types that can determine their own plural form.
type Interface interface {
// PluralForm reports the plural form for the given language of the
// underlying value. It also returns the integer value. If the integer value
// is larger than fits in n, PluralForm may return a value modulo
// 10,000,000.
PluralForm(t language.Tag, scale int) (f Form, n int)
}
// Selectf returns the first case for which its selector is a match for the
// arg-th substitution argument to a formatting call, formatting it as indicated
// by format.
//
// The cases argument are pairs of selectors and messages. Selectors are of type
// string or Form. Messages are of type string or catalog.Message. A selector
// matches an argument if:
// - it is "other" or Other
// - it matches the plural form of the argument: "zero", "one", "two", "few",
// or "many", or the equivalent Form
// - it is of the form "=x" where x is an integer that matches the value of
// the argument.
// - it is of the form "<x" where x is an integer that is larger than the
// argument.
//
// The format argument determines the formatting parameters for which to
// determine the plural form. This is especially relevant for non-integer
// values.
//
// The format string may be "", in which case a best-effort attempt is made to
// find a reasonable representation on which to base the plural form. Examples
// of format strings are:
// - %.2f decimal with scale 2
// - %.2e scientific notation with precision 3 (scale + 1)
// - %d integer
func Selectf(arg int, format string, cases ...interface{}) catalog.Message {
var p parser
// Intercept the formatting parameters of format by doing a dummy print.
fmt.Fprintf(ioutil.Discard, format, &p)
m := &message{arg, kindDefault, 0, cases}
switch p.verb {
case 'g':
m.kind = kindPrecision
m.scale = p.scale
case 'f':
m.kind = kindScale
m.scale = p.scale
case 'e':
m.kind = kindScientific
m.scale = p.scale
case 'd':
m.kind = kindScale
m.scale = 0
default:
// TODO: do we need to handle errors?
}
return m
}
type parser struct {
verb rune
scale int
}
func (p *parser) Format(s fmt.State, verb rune) {
p.verb = verb
p.scale = -1
if prec, ok := s.Precision(); ok {
p.scale = prec
}
}
type message struct {
arg int
kind int
scale int
cases []interface{}
}
const (
// Start with non-ASCII to allow skipping values.
kindDefault = 0x80 + iota
kindScale // verb f, number of fraction digits follows
kindScientific // verb e, number of fraction digits follows
kindPrecision // verb g, number of significant digits follows
)
var handle = catmsg.Register("golang.org/x/text/feature/plural:plural", execute)
func (m *message) Compile(e *catmsg.Encoder) error {
e.EncodeMessageType(handle)
e.EncodeUint(uint64(m.arg))
e.EncodeUint(uint64(m.kind))
if m.kind > kindDefault {
e.EncodeUint(uint64(m.scale))
}
forms := validForms(cardinal, e.Language())
for i := 0; i < len(m.cases); {
if err := compileSelector(e, forms, m.cases[i]); err != nil {
return err
}
if i++; i >= len(m.cases) {
return fmt.Errorf("plural: no message defined for selector %v", m.cases[i-1])
}
var msg catalog.Message
switch x := m.cases[i].(type) {
case string:
msg = catalog.String(x)
case catalog.Message:
msg = x
default:
return fmt.Errorf("plural: message of type %T; must be string or catalog.Message", x)
}
if err := e.EncodeMessage(msg); err != nil {
return err
}
i++
}
return nil
}
func compileSelector(e *catmsg.Encoder, valid []Form, selector interface{}) error {
form := Other
switch x := selector.(type) {
case string:
if x == "" {
return fmt.Errorf("plural: empty selector")
}
if c := x[0]; c == '=' || c == '<' {
val, err := strconv.ParseUint(x[1:], 10, 16)
if err != nil {
return fmt.Errorf("plural: invalid number in selector %q: %v", selector, err)
}
e.EncodeUint(uint64(c))
e.EncodeUint(val)
return nil
}
var ok bool
form, ok = countMap[x]
if !ok {
return fmt.Errorf("plural: invalid plural form %q", selector)
}
case Form:
form = x
default:
return fmt.Errorf("plural: selector of type %T; want string or Form", selector)
}
ok := false
for _, f := range valid {
if f == form {
ok = true
break
}
}
if !ok {
return fmt.Errorf("plural: form %q not supported for language %q", selector, e.Language())
}
e.EncodeUint(uint64(form))
return nil
}
func execute(d *catmsg.Decoder) bool {
lang := d.Language()
argN := int(d.DecodeUint())
kind := int(d.DecodeUint())
scale := -1 // default
if kind > kindDefault {
scale = int(d.DecodeUint())
}
form := Other
n := -1
if arg := d.Arg(argN); arg == nil {
// Default to Other.
} else if x, ok := arg.(number.VisibleDigits); ok {
d := x.Digits(nil, lang, scale)
form, n = cardinal.matchDisplayDigits(lang, &d)
} else if x, ok := arg.(Interface); ok {
// This covers lists and formatters from the number package.
form, n = x.PluralForm(lang, scale)
} else {
var f number.Formatter
switch kind {
case kindScale:
f.InitDecimal(lang)
f.SetScale(scale)
case kindScientific:
f.InitScientific(lang)
f.SetScale(scale)
case kindPrecision:
f.InitDecimal(lang)
f.SetPrecision(scale)
case kindDefault:
// sensible default
f.InitDecimal(lang)
if k := reflect.TypeOf(arg).Kind(); reflect.Int <= k && k <= reflect.Uintptr {
f.SetScale(0)
} else {
f.SetScale(2)
}
}
var dec number.Decimal // TODO: buffer in Printer
dec.Convert(f.RoundingContext, arg)
v := number.FormatDigits(&dec, f.RoundingContext)
if !v.NaN && !v.Inf {
form, n = cardinal.matchDisplayDigits(d.Language(), &v)
}
}
for !d.Done() {
f := d.DecodeUint()
if (f == '=' && n == int(d.DecodeUint())) ||
(f == '<' && 0 <= n && n < int(d.DecodeUint())) ||
form == Form(f) ||
Other == Form(f) {
return d.ExecuteMessage()
}
d.SkipMessage()
}
return false
}
+261
View File
@@ -0,0 +1,261 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run gen.go gen_common.go
// Package plural provides utilities for handling linguistic plurals in text.
//
// The definitions in this package are based on the plural rule handling defined
// in CLDR. See
// https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules for
// details.
package plural
import (
"golang.org/x/text/internal/language/compact"
"golang.org/x/text/internal/number"
"golang.org/x/text/language"
)
// Rules defines the plural rules for all languages for a certain plural type.
//
//
// This package is UNDER CONSTRUCTION and its API may change.
type Rules struct {
rules []pluralCheck
index []byte
langToIndex []byte
inclusionMasks []uint64
}
var (
// Cardinal defines the plural rules for numbers indicating quantities.
Cardinal *Rules = cardinal
// Ordinal defines the plural rules for numbers indicating position
// (first, second, etc.).
Ordinal *Rules = ordinal
ordinal = &Rules{
ordinalRules,
ordinalIndex,
ordinalLangToIndex,
ordinalInclusionMasks[:],
}
cardinal = &Rules{
cardinalRules,
cardinalIndex,
cardinalLangToIndex,
cardinalInclusionMasks[:],
}
)
// getIntApprox converts the digits in slice digits[start:end] to an integer
// according to the following rules:
// - Let i be asInt(digits[start:end]), where out-of-range digits are assumed
// to be zero.
// - Result n is big if i / 10^nMod > 1.
// - Otherwise the result is i % 10^nMod.
//
// For example, if digits is {1, 2, 3} and start:end is 0:5, then the result
// for various values of nMod is:
// - when nMod == 2, n == big
// - when nMod == 3, n == big
// - when nMod == 4, n == big
// - when nMod == 5, n == 12300
// - when nMod == 6, n == 12300
// - when nMod == 7, n == 12300
func getIntApprox(digits []byte, start, end, nMod, big int) (n int) {
// Leading 0 digits just result in 0.
p := start
if p < 0 {
p = 0
}
// Range only over the part for which we have digits.
mid := end
if mid >= len(digits) {
mid = len(digits)
}
// Check digits more significant that nMod.
if q := end - nMod; q > 0 {
if q > mid {
q = mid
}
for ; p < q; p++ {
if digits[p] != 0 {
return big
}
}
}
for ; p < mid; p++ {
n = 10*n + int(digits[p])
}
// Multiply for trailing zeros.
for ; p < end; p++ {
n *= 10
}
return n
}
// MatchDigits computes the plural form for the given language and the given
// decimal floating point digits. The digits are stored in big-endian order and
// are of value byte(0) - byte(9). The floating point position is indicated by
// exp and the number of visible decimals is scale. All leading and trailing
// zeros may be omitted from digits.
//
// The following table contains examples of possible arguments to represent
// the given numbers.
// decimal digits exp scale
// 123 []byte{1, 2, 3} 3 0
// 123.4 []byte{1, 2, 3, 4} 3 1
// 123.40 []byte{1, 2, 3, 4} 3 2
// 100000 []byte{1} 6 0
// 100000.00 []byte{1} 6 3
func (p *Rules) MatchDigits(t language.Tag, digits []byte, exp, scale int) Form {
index := tagToID(t)
// Differentiate up to including mod 1000000 for the integer part.
n := getIntApprox(digits, 0, exp, 6, 1000000)
// Differentiate up to including mod 100 for the fractional part.
f := getIntApprox(digits, exp, exp+scale, 2, 100)
return matchPlural(p, index, n, f, scale)
}
func (p *Rules) matchDisplayDigits(t language.Tag, d *number.Digits) (Form, int) {
n := getIntApprox(d.Digits, 0, int(d.Exp), 6, 1000000)
return p.MatchDigits(t, d.Digits, int(d.Exp), d.NumFracDigits()), n
}
func validForms(p *Rules, t language.Tag) (forms []Form) {
offset := p.langToIndex[tagToID(t)]
rules := p.rules[p.index[offset]:p.index[offset+1]]
forms = append(forms, Other)
last := Other
for _, r := range rules {
if cat := Form(r.cat & formMask); cat != andNext && last != cat {
forms = append(forms, cat)
last = cat
}
}
return forms
}
func (p *Rules) matchComponents(t language.Tag, n, f, scale int) Form {
return matchPlural(p, tagToID(t), n, f, scale)
}
// MatchPlural returns the plural form for the given language and plural
// operands (as defined in
// https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules):
// where
// n absolute value of the source number (integer and decimals)
// input
// i integer digits of n.
// v number of visible fraction digits in n, with trailing zeros.
// w number of visible fraction digits in n, without trailing zeros.
// f visible fractional digits in n, with trailing zeros (f = t * 10^(v-w))
// t visible fractional digits in n, without trailing zeros.
//
// If any of the operand values is too large to fit in an int, it is okay to
// pass the value modulo 10,000,000.
func (p *Rules) MatchPlural(lang language.Tag, i, v, w, f, t int) Form {
return matchPlural(p, tagToID(lang), i, f, v)
}
func matchPlural(p *Rules, index compact.ID, n, f, v int) Form {
nMask := p.inclusionMasks[n%maxMod]
// Compute the fMask inline in the rules below, as it is relatively rare.
// fMask := p.inclusionMasks[f%maxMod]
vMask := p.inclusionMasks[v%maxMod]
// Do the matching
offset := p.langToIndex[index]
rules := p.rules[p.index[offset]:p.index[offset+1]]
for i := 0; i < len(rules); i++ {
rule := rules[i]
setBit := uint64(1 << rule.setID)
var skip bool
switch op := opID(rule.cat >> opShift); op {
case opI: // i = x
skip = n >= numN || nMask&setBit == 0
case opI | opNotEqual: // i != x
skip = n < numN && nMask&setBit != 0
case opI | opMod: // i % m = x
skip = nMask&setBit == 0
case opI | opMod | opNotEqual: // i % m != x
skip = nMask&setBit != 0
case opN: // n = x
skip = f != 0 || n >= numN || nMask&setBit == 0
case opN | opNotEqual: // n != x
skip = f == 0 && n < numN && nMask&setBit != 0
case opN | opMod: // n % m = x
skip = f != 0 || nMask&setBit == 0
case opN | opMod | opNotEqual: // n % m != x
skip = f == 0 && nMask&setBit != 0
case opF: // f = x
skip = f >= numN || p.inclusionMasks[f%maxMod]&setBit == 0
case opF | opNotEqual: // f != x
skip = f < numN && p.inclusionMasks[f%maxMod]&setBit != 0
case opF | opMod: // f % m = x
skip = p.inclusionMasks[f%maxMod]&setBit == 0
case opF | opMod | opNotEqual: // f % m != x
skip = p.inclusionMasks[f%maxMod]&setBit != 0
case opV: // v = x
skip = v < numN && vMask&setBit == 0
case opV | opNotEqual: // v != x
skip = v < numN && vMask&setBit != 0
case opW: // w == 0
skip = f != 0
case opW | opNotEqual: // w != 0
skip = f == 0
// Hard-wired rules that cannot be handled by our algorithm.
case opBretonM:
skip = f != 0 || n == 0 || n%1000000 != 0
case opAzerbaijan00s:
// 100,200,300,400,500,600,700,800,900
skip = n == 0 || n >= 1000 || n%100 != 0
case opItalian800:
skip = (f != 0 || n >= numN || nMask&setBit == 0) && n != 800
}
if skip {
// advance over AND entries.
for ; i < len(rules) && rules[i].cat&formMask == andNext; i++ {
}
continue
}
// return if we have a final entry.
if cat := rule.cat & formMask; cat != andNext {
return Form(cat)
}
}
return Other
}
func tagToID(t language.Tag) compact.ID {
id, _ := compact.RegionalID(compact.Tag(t))
return id
}
+552
View File
@@ -0,0 +1,552 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package plural
// CLDRVersion is the CLDR version from which the tables in this package are derived.
const CLDRVersion = "32"
var ordinalRules = []pluralCheck{ // 64 elements
0: {cat: 0x2f, setID: 0x4},
1: {cat: 0x3a, setID: 0x5},
2: {cat: 0x22, setID: 0x1},
3: {cat: 0x22, setID: 0x6},
4: {cat: 0x22, setID: 0x7},
5: {cat: 0x2f, setID: 0x8},
6: {cat: 0x3c, setID: 0x9},
7: {cat: 0x2f, setID: 0xa},
8: {cat: 0x3c, setID: 0xb},
9: {cat: 0x2c, setID: 0xc},
10: {cat: 0x24, setID: 0xd},
11: {cat: 0x2d, setID: 0xe},
12: {cat: 0x2d, setID: 0xf},
13: {cat: 0x2f, setID: 0x10},
14: {cat: 0x35, setID: 0x3},
15: {cat: 0xc5, setID: 0x11},
16: {cat: 0x2, setID: 0x1},
17: {cat: 0x5, setID: 0x3},
18: {cat: 0xd, setID: 0x12},
19: {cat: 0x22, setID: 0x1},
20: {cat: 0x2f, setID: 0x13},
21: {cat: 0x3d, setID: 0x14},
22: {cat: 0x2f, setID: 0x15},
23: {cat: 0x3a, setID: 0x16},
24: {cat: 0x2f, setID: 0x17},
25: {cat: 0x3b, setID: 0x18},
26: {cat: 0x2f, setID: 0xa},
27: {cat: 0x3c, setID: 0xb},
28: {cat: 0x22, setID: 0x1},
29: {cat: 0x23, setID: 0x19},
30: {cat: 0x24, setID: 0x1a},
31: {cat: 0x22, setID: 0x1b},
32: {cat: 0x23, setID: 0x2},
33: {cat: 0x24, setID: 0x1a},
34: {cat: 0xf, setID: 0x15},
35: {cat: 0x1a, setID: 0x16},
36: {cat: 0xf, setID: 0x17},
37: {cat: 0x1b, setID: 0x18},
38: {cat: 0xf, setID: 0x1c},
39: {cat: 0x1d, setID: 0x1d},
40: {cat: 0xa, setID: 0x1e},
41: {cat: 0xa, setID: 0x1f},
42: {cat: 0xc, setID: 0x20},
43: {cat: 0xe4, setID: 0x0},
44: {cat: 0x5, setID: 0x3},
45: {cat: 0xd, setID: 0xe},
46: {cat: 0xd, setID: 0x21},
47: {cat: 0x22, setID: 0x1},
48: {cat: 0x23, setID: 0x19},
49: {cat: 0x24, setID: 0x1a},
50: {cat: 0x25, setID: 0x22},
51: {cat: 0x22, setID: 0x23},
52: {cat: 0x23, setID: 0x19},
53: {cat: 0x24, setID: 0x1a},
54: {cat: 0x25, setID: 0x22},
55: {cat: 0x22, setID: 0x24},
56: {cat: 0x23, setID: 0x19},
57: {cat: 0x24, setID: 0x1a},
58: {cat: 0x25, setID: 0x22},
59: {cat: 0x21, setID: 0x25},
60: {cat: 0x22, setID: 0x1},
61: {cat: 0x23, setID: 0x2},
62: {cat: 0x24, setID: 0x26},
63: {cat: 0x25, setID: 0x27},
} // Size: 152 bytes
var ordinalIndex = []uint8{ // 22 elements
0x00, 0x00, 0x02, 0x03, 0x04, 0x05, 0x07, 0x09,
0x0b, 0x0f, 0x10, 0x13, 0x16, 0x1c, 0x1f, 0x22,
0x28, 0x2f, 0x33, 0x37, 0x3b, 0x40,
} // Size: 46 bytes
var ordinalLangToIndex = []uint8{ // 775 elements
// Entry 0 - 3F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,
0x10, 0x10, 0x10, 0x00, 0x00, 0x05, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 40 - 7F
0x12, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e,
0x0e, 0x0e, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 80 - BF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
// Entry C0 - FF
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 100 - 13F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02,
0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
// Entry 140 - 17F
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11,
0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 180 - 1BF
0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09, 0x09,
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0a, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 1C0 - 1FF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00,
0x00, 0x00, 0x02, 0x0d, 0x0d, 0x02, 0x02, 0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 200 - 23F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x13, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 240 - 27F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 280 - 2BF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0b, 0x0b, 0x0b, 0x0b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x07, 0x02, 0x00, 0x00, 0x00, 0x00,
// Entry 2C0 - 2FF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 300 - 33F
0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x0c,
} // Size: 799 bytes
var ordinalInclusionMasks = []uint64{ // 100 elements
// Entry 0 - 1F
0x0000002000010009, 0x00000018482000d3, 0x0000000042840195, 0x000000410a040581,
0x00000041040c0081, 0x0000009840040041, 0x0000008400045001, 0x0000003850040001,
0x0000003850060001, 0x0000003800049001, 0x0000000800052001, 0x0000000040660031,
0x0000000041840331, 0x0000000100040f01, 0x00000001001c0001, 0x0000000040040001,
0x0000000000045001, 0x0000000070040001, 0x0000000070040001, 0x0000000000049001,
0x0000000080050001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
0x0000000050000001, 0x0000000000009001, 0x0000000000010001, 0x0000000040200011,
// Entry 20 - 3F
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
0x0000000200050001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
0x0000000050000001, 0x0000000000009001, 0x0000000080010001, 0x0000000040200011,
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
0x0000000200050001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
// Entry 40 - 5F
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
0x0000000050000001, 0x0000000000009001, 0x0000000080010001, 0x0000000040200011,
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
0x0000000080070001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
0x0000000050000001, 0x0000000000009001, 0x0000000200010001, 0x0000000040200011,
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
// Entry 60 - 7F
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
} // Size: 824 bytes
// Slots used for ordinal: 40 of 0xFF rules; 16 of 0xFF indexes; 40 of 64 sets
var cardinalRules = []pluralCheck{ // 166 elements
0: {cat: 0x2, setID: 0x3},
1: {cat: 0x22, setID: 0x1},
2: {cat: 0x2, setID: 0x4},
3: {cat: 0x2, setID: 0x4},
4: {cat: 0x7, setID: 0x1},
5: {cat: 0x62, setID: 0x3},
6: {cat: 0x22, setID: 0x4},
7: {cat: 0x7, setID: 0x3},
8: {cat: 0x42, setID: 0x1},
9: {cat: 0x22, setID: 0x4},
10: {cat: 0x22, setID: 0x4},
11: {cat: 0x22, setID: 0x5},
12: {cat: 0x22, setID: 0x1},
13: {cat: 0x22, setID: 0x1},
14: {cat: 0x7, setID: 0x4},
15: {cat: 0x92, setID: 0x3},
16: {cat: 0xf, setID: 0x6},
17: {cat: 0x1f, setID: 0x7},
18: {cat: 0x82, setID: 0x3},
19: {cat: 0x92, setID: 0x3},
20: {cat: 0xf, setID: 0x6},
21: {cat: 0x62, setID: 0x3},
22: {cat: 0x4a, setID: 0x6},
23: {cat: 0x7, setID: 0x8},
24: {cat: 0x62, setID: 0x3},
25: {cat: 0x1f, setID: 0x9},
26: {cat: 0x62, setID: 0x3},
27: {cat: 0x5f, setID: 0x9},
28: {cat: 0x72, setID: 0x3},
29: {cat: 0x29, setID: 0xa},
30: {cat: 0x29, setID: 0xb},
31: {cat: 0x4f, setID: 0xb},
32: {cat: 0x61, setID: 0x2},
33: {cat: 0x2f, setID: 0x6},
34: {cat: 0x3a, setID: 0x7},
35: {cat: 0x4f, setID: 0x6},
36: {cat: 0x5f, setID: 0x7},
37: {cat: 0x62, setID: 0x2},
38: {cat: 0x4f, setID: 0x6},
39: {cat: 0x72, setID: 0x2},
40: {cat: 0x21, setID: 0x3},
41: {cat: 0x7, setID: 0x4},
42: {cat: 0x32, setID: 0x3},
43: {cat: 0x21, setID: 0x3},
44: {cat: 0x22, setID: 0x1},
45: {cat: 0x22, setID: 0x1},
46: {cat: 0x23, setID: 0x2},
47: {cat: 0x2, setID: 0x3},
48: {cat: 0x22, setID: 0x1},
49: {cat: 0x24, setID: 0xc},
50: {cat: 0x7, setID: 0x1},
51: {cat: 0x62, setID: 0x3},
52: {cat: 0x74, setID: 0x3},
53: {cat: 0x24, setID: 0x3},
54: {cat: 0x2f, setID: 0xd},
55: {cat: 0x34, setID: 0x1},
56: {cat: 0xf, setID: 0x6},
57: {cat: 0x1f, setID: 0x7},
58: {cat: 0x62, setID: 0x3},
59: {cat: 0x4f, setID: 0x6},
60: {cat: 0x5a, setID: 0x7},
61: {cat: 0xf, setID: 0xe},
62: {cat: 0x1f, setID: 0xf},
63: {cat: 0x64, setID: 0x3},
64: {cat: 0x4f, setID: 0xe},
65: {cat: 0x5c, setID: 0xf},
66: {cat: 0x22, setID: 0x10},
67: {cat: 0x23, setID: 0x11},
68: {cat: 0x24, setID: 0x12},
69: {cat: 0xf, setID: 0x1},
70: {cat: 0x62, setID: 0x3},
71: {cat: 0xf, setID: 0x2},
72: {cat: 0x63, setID: 0x3},
73: {cat: 0xf, setID: 0x13},
74: {cat: 0x64, setID: 0x3},
75: {cat: 0x74, setID: 0x3},
76: {cat: 0xf, setID: 0x1},
77: {cat: 0x62, setID: 0x3},
78: {cat: 0x4a, setID: 0x1},
79: {cat: 0xf, setID: 0x2},
80: {cat: 0x63, setID: 0x3},
81: {cat: 0x4b, setID: 0x2},
82: {cat: 0xf, setID: 0x13},
83: {cat: 0x64, setID: 0x3},
84: {cat: 0x4c, setID: 0x13},
85: {cat: 0x7, setID: 0x1},
86: {cat: 0x62, setID: 0x3},
87: {cat: 0x7, setID: 0x2},
88: {cat: 0x63, setID: 0x3},
89: {cat: 0x2f, setID: 0xa},
90: {cat: 0x37, setID: 0x14},
91: {cat: 0x65, setID: 0x3},
92: {cat: 0x7, setID: 0x1},
93: {cat: 0x62, setID: 0x3},
94: {cat: 0x7, setID: 0x15},
95: {cat: 0x64, setID: 0x3},
96: {cat: 0x75, setID: 0x3},
97: {cat: 0x7, setID: 0x1},
98: {cat: 0x62, setID: 0x3},
99: {cat: 0xf, setID: 0xe},
100: {cat: 0x1f, setID: 0xf},
101: {cat: 0x64, setID: 0x3},
102: {cat: 0xf, setID: 0x16},
103: {cat: 0x17, setID: 0x1},
104: {cat: 0x65, setID: 0x3},
105: {cat: 0xf, setID: 0x17},
106: {cat: 0x65, setID: 0x3},
107: {cat: 0xf, setID: 0xf},
108: {cat: 0x65, setID: 0x3},
109: {cat: 0x2f, setID: 0x6},
110: {cat: 0x3a, setID: 0x7},
111: {cat: 0x2f, setID: 0xe},
112: {cat: 0x3c, setID: 0xf},
113: {cat: 0x2d, setID: 0xa},
114: {cat: 0x2d, setID: 0x17},
115: {cat: 0x2d, setID: 0x18},
116: {cat: 0x2f, setID: 0x6},
117: {cat: 0x3a, setID: 0xb},
118: {cat: 0x2f, setID: 0x19},
119: {cat: 0x3c, setID: 0xb},
120: {cat: 0x55, setID: 0x3},
121: {cat: 0x22, setID: 0x1},
122: {cat: 0x24, setID: 0x3},
123: {cat: 0x2c, setID: 0xc},
124: {cat: 0x2d, setID: 0xb},
125: {cat: 0xf, setID: 0x6},
126: {cat: 0x1f, setID: 0x7},
127: {cat: 0x62, setID: 0x3},
128: {cat: 0xf, setID: 0xe},
129: {cat: 0x1f, setID: 0xf},
130: {cat: 0x64, setID: 0x3},
131: {cat: 0xf, setID: 0xa},
132: {cat: 0x65, setID: 0x3},
133: {cat: 0xf, setID: 0x17},
134: {cat: 0x65, setID: 0x3},
135: {cat: 0xf, setID: 0x18},
136: {cat: 0x65, setID: 0x3},
137: {cat: 0x2f, setID: 0x6},
138: {cat: 0x3a, setID: 0x1a},
139: {cat: 0x2f, setID: 0x1b},
140: {cat: 0x3b, setID: 0x1c},
141: {cat: 0x2f, setID: 0x1d},
142: {cat: 0x3c, setID: 0x1e},
143: {cat: 0x37, setID: 0x3},
144: {cat: 0xa5, setID: 0x0},
145: {cat: 0x22, setID: 0x1},
146: {cat: 0x23, setID: 0x2},
147: {cat: 0x24, setID: 0x1f},
148: {cat: 0x25, setID: 0x20},
149: {cat: 0xf, setID: 0x6},
150: {cat: 0x62, setID: 0x3},
151: {cat: 0xf, setID: 0x1b},
152: {cat: 0x63, setID: 0x3},
153: {cat: 0xf, setID: 0x21},
154: {cat: 0x64, setID: 0x3},
155: {cat: 0x75, setID: 0x3},
156: {cat: 0x21, setID: 0x3},
157: {cat: 0x22, setID: 0x1},
158: {cat: 0x23, setID: 0x2},
159: {cat: 0x2c, setID: 0x22},
160: {cat: 0x2d, setID: 0x5},
161: {cat: 0x21, setID: 0x3},
162: {cat: 0x22, setID: 0x1},
163: {cat: 0x23, setID: 0x2},
164: {cat: 0x24, setID: 0x23},
165: {cat: 0x25, setID: 0x24},
} // Size: 356 bytes
var cardinalIndex = []uint8{ // 36 elements
0x00, 0x00, 0x02, 0x03, 0x04, 0x06, 0x09, 0x0a,
0x0c, 0x0d, 0x10, 0x14, 0x17, 0x1d, 0x28, 0x2b,
0x2d, 0x2f, 0x32, 0x38, 0x42, 0x45, 0x4c, 0x55,
0x5c, 0x61, 0x6d, 0x74, 0x79, 0x7d, 0x89, 0x91,
0x95, 0x9c, 0xa1, 0xa6,
} // Size: 60 bytes
var cardinalLangToIndex = []uint8{ // 775 elements
// Entry 0 - 3F
0x00, 0x08, 0x08, 0x08, 0x00, 0x00, 0x06, 0x06,
0x01, 0x01, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21,
0x01, 0x01, 0x08, 0x08, 0x04, 0x04, 0x08, 0x08,
0x08, 0x08, 0x08, 0x00, 0x00, 0x1a, 0x1a, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x06, 0x00, 0x00,
// Entry 40 - 7F
0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x1e,
0x08, 0x08, 0x13, 0x13, 0x13, 0x13, 0x13, 0x04,
0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x18, 0x18, 0x00, 0x00, 0x22, 0x22, 0x09, 0x09,
0x09, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x00, 0x00, 0x16, 0x16, 0x00,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 80 - BF
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
// Entry C0 - FF
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
// Entry 100 - 13F
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04,
0x08, 0x08, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02,
0x02, 0x02, 0x02, 0x02, 0x04, 0x04, 0x0c, 0x0c,
0x08, 0x08, 0x08, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
// Entry 140 - 17F
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x08, 0x08, 0x04, 0x04, 0x1f, 0x1f,
0x14, 0x14, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08,
0x01, 0x01, 0x06, 0x00, 0x00, 0x20, 0x20, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x17, 0x17, 0x01,
0x01, 0x13, 0x13, 0x13, 0x16, 0x16, 0x08, 0x08,
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 180 - 1BF
0x00, 0x04, 0x0a, 0x0a, 0x04, 0x04, 0x04, 0x04,
0x04, 0x10, 0x17, 0x00, 0x00, 0x00, 0x08, 0x08,
0x04, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x02,
0x02, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
0x08, 0x08, 0x00, 0x00, 0x0f, 0x0f, 0x08, 0x10,
// Entry 1C0 - 1FF
0x10, 0x08, 0x08, 0x0e, 0x0e, 0x08, 0x08, 0x08,
0x08, 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0d, 0x08,
0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
0x00, 0x00, 0x08, 0x08, 0x0b, 0x0b, 0x08, 0x08,
0x08, 0x08, 0x12, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 200 - 23F
0x00, 0x08, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08,
0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08,
0x06, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x06, 0x06,
0x06, 0x06, 0x06, 0x08, 0x19, 0x19, 0x0d, 0x0d,
0x08, 0x08, 0x03, 0x04, 0x03, 0x04, 0x04, 0x04,
// Entry 240 - 27F
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00,
0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x12,
0x12, 0x12, 0x08, 0x08, 0x1d, 0x1d, 0x1d, 0x1d,
0x1d, 0x1d, 0x1d, 0x00, 0x00, 0x08, 0x08, 0x00,
0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08, 0x08,
0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00,
0x00, 0x00, 0x13, 0x11, 0x11, 0x11, 0x11, 0x11,
0x05, 0x05, 0x18, 0x18, 0x15, 0x15, 0x10, 0x10,
// Entry 280 - 2BF
0x10, 0x10, 0x10, 0x10, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x13,
0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
0x13, 0x13, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x06,
0x08, 0x08, 0x08, 0x0c, 0x08, 0x00, 0x00, 0x08,
// Entry 2C0 - 2FF
0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x07,
0x07, 0x08, 0x08, 0x1d, 0x1d, 0x04, 0x04, 0x04,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08,
0x08, 0x08, 0x08, 0x06, 0x08, 0x08, 0x00, 0x00,
0x08, 0x08, 0x08, 0x00, 0x00, 0x04, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 300 - 33F
0x00, 0x00, 0x00, 0x01, 0x01, 0x04, 0x04,
} // Size: 799 bytes
var cardinalInclusionMasks = []uint64{ // 100 elements
// Entry 0 - 1F
0x0000000200500419, 0x0000000000512153, 0x000000000a327105, 0x0000000ca23c7101,
0x00000004a23c7201, 0x0000000482943001, 0x0000001482943201, 0x0000000502943001,
0x0000000502943001, 0x0000000522943201, 0x0000000540543401, 0x00000000454128e1,
0x000000005b02e821, 0x000000006304e821, 0x000000006304ea21, 0x0000000042842821,
0x0000000042842a21, 0x0000000042842821, 0x0000000042842821, 0x0000000062842a21,
0x0000000200400421, 0x0000000000400061, 0x000000000a004021, 0x0000000022004021,
0x0000000022004221, 0x0000000002800021, 0x0000000002800221, 0x0000000002800021,
0x0000000002800021, 0x0000000022800221, 0x0000000000400421, 0x0000000000400061,
// Entry 20 - 3F
0x000000000a004021, 0x0000000022004021, 0x0000000022004221, 0x0000000002800021,
0x0000000002800221, 0x0000000002800021, 0x0000000002800021, 0x0000000022800221,
0x0000000200400421, 0x0000000000400061, 0x000000000a004021, 0x0000000022004021,
0x0000000022004221, 0x0000000002800021, 0x0000000002800221, 0x0000000002800021,
0x0000000002800021, 0x0000000022800221, 0x0000000000400421, 0x0000000000400061,
0x000000000a004021, 0x0000000022004021, 0x0000000022004221, 0x0000000002800021,
0x0000000002800221, 0x0000000002800021, 0x0000000002800021, 0x0000000022800221,
0x0000000200400421, 0x0000000000400061, 0x000000000a004021, 0x0000000022004021,
// Entry 40 - 5F
0x0000000022004221, 0x0000000002800021, 0x0000000002800221, 0x0000000002800021,
0x0000000002800021, 0x0000000022800221, 0x0000000040400421, 0x0000000044400061,
0x000000005a004021, 0x0000000062004021, 0x0000000062004221, 0x0000000042800021,
0x0000000042800221, 0x0000000042800021, 0x0000000042800021, 0x0000000062800221,
0x0000000200400421, 0x0000000000400061, 0x000000000a004021, 0x0000000022004021,
0x0000000022004221, 0x0000000002800021, 0x0000000002800221, 0x0000000002800021,
0x0000000002800021, 0x0000000022800221, 0x0000000040400421, 0x0000000044400061,
0x000000005a004021, 0x0000000062004021, 0x0000000062004221, 0x0000000042800021,
// Entry 60 - 7F
0x0000000042800221, 0x0000000042800021, 0x0000000042800021, 0x0000000062800221,
} // Size: 824 bytes
// Slots used for cardinal: A6 of 0xFF rules; 24 of 0xFF indexes; 37 of 64 sets
// Total table size 3860 bytes (3KiB); checksum: 4E56F7B1
+415
View File
@@ -0,0 +1,415 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package catmsg contains support types for package x/text/message/catalog.
//
// This package contains the low-level implementations of Message used by the
// catalog package and provides primitives for other packages to implement their
// own. For instance, the plural package provides functionality for selecting
// translation strings based on the plural category of substitution arguments.
//
//
// Encoding and Decoding
//
// Catalogs store Messages encoded as a single string. Compiling a message into
// a string both results in compacter representation and speeds up evaluation.
//
// A Message must implement a Compile method to convert its arbitrary
// representation to a string. The Compile method takes an Encoder which
// facilitates serializing the message. Encoders also provide more context of
// the messages's creation (such as for which language the message is intended),
// which may not be known at the time of the creation of the message.
//
// Each message type must also have an accompanying decoder registered to decode
// the message. This decoder takes a Decoder argument which provides the
// counterparts for the decoding.
//
//
// Renderers
//
// A Decoder must be initialized with a Renderer implementation. These
// implementations must be provided by packages that use Catalogs, typically
// formatting packages such as x/text/message. A typical user will not need to
// worry about this type; it is only relevant to packages that do string
// formatting and want to use the catalog package to handle localized strings.
//
// A package that uses catalogs for selecting strings receives selection results
// as sequence of substrings passed to the Renderer. The following snippet shows
// how to express the above example using the message package.
//
// message.Set(language.English, "You are %d minute(s) late.",
// catalog.Var("minutes", plural.Select(1, "one", "minute")),
// catalog.String("You are %[1]d ${minutes} late."))
//
// p := message.NewPrinter(language.English)
// p.Printf("You are %d minute(s) late.", 5) // always 5 minutes late.
//
// To evaluate the Printf, package message wraps the arguments in a Renderer
// that is passed to the catalog for message decoding. The call sequence that
// results from evaluating the above message, assuming the person is rather
// tardy, is:
//
// Render("You are %[1]d ")
// Arg(1)
// Render("minutes")
// Render(" late.")
//
// The calls to Arg is caused by the plural.Select execution, which evaluates
// the argument to determine whether the singular or plural message form should
// be selected. The calls to Render reports the partial results to the message
// package for further evaluation.
package catmsg
import (
"errors"
"fmt"
"strconv"
"strings"
"sync"
"golang.org/x/text/language"
)
// A Handle refers to a registered message type.
type Handle int
// A Handler decodes and evaluates data compiled by a Message and sends the
// result to the Decoder. The output may depend on the value of the substitution
// arguments, accessible by the Decoder's Arg method. The Handler returns false
// if there is no translation for the given substitution arguments.
type Handler func(d *Decoder) bool
// Register records the existence of a message type and returns a Handle that
// can be used in the Encoder's EncodeMessageType method to create such
// messages. The prefix of the name should be the package path followed by
// an optional disambiguating string.
// Register will panic if a handle for the same name was already registered.
func Register(name string, handler Handler) Handle {
mutex.Lock()
defer mutex.Unlock()
if _, ok := names[name]; ok {
panic(fmt.Errorf("catmsg: handler for %q already exists", name))
}
h := Handle(len(handlers))
names[name] = h
handlers = append(handlers, handler)
return h
}
// These handlers require fixed positions in the handlers slice.
const (
msgVars Handle = iota
msgFirst
msgRaw
msgString
msgAffix
// Leave some arbitrary room for future expansion: 20 should suffice.
numInternal = 20
)
const prefix = "golang.org/x/text/internal/catmsg."
var (
// TODO: find a more stable way to link handles to message types.
mutex sync.Mutex
names = map[string]Handle{
prefix + "Vars": msgVars,
prefix + "First": msgFirst,
prefix + "Raw": msgRaw,
prefix + "String": msgString,
prefix + "Affix": msgAffix,
}
handlers = make([]Handler, numInternal)
)
func init() {
// This handler is a message type wrapper that initializes a decoder
// with a variable block. This message type, if present, is always at the
// start of an encoded message.
handlers[msgVars] = func(d *Decoder) bool {
blockSize := int(d.DecodeUint())
d.vars = d.data[:blockSize]
d.data = d.data[blockSize:]
return d.executeMessage()
}
// First takes the first message in a sequence that results in a match for
// the given substitution arguments.
handlers[msgFirst] = func(d *Decoder) bool {
for !d.Done() {
if d.ExecuteMessage() {
return true
}
}
return false
}
handlers[msgRaw] = func(d *Decoder) bool {
d.Render(d.data)
return true
}
// A String message alternates between a string constant and a variable
// substitution.
handlers[msgString] = func(d *Decoder) bool {
for !d.Done() {
if str := d.DecodeString(); str != "" {
d.Render(str)
}
if d.Done() {
break
}
d.ExecuteSubstitution()
}
return true
}
handlers[msgAffix] = func(d *Decoder) bool {
// TODO: use an alternative method for common cases.
prefix := d.DecodeString()
suffix := d.DecodeString()
if prefix != "" {
d.Render(prefix)
}
ret := d.ExecuteMessage()
if suffix != "" {
d.Render(suffix)
}
return ret
}
}
var (
// ErrIncomplete indicates a compiled message does not define translations
// for all possible argument values. If this message is returned, evaluating
// a message may result in the ErrNoMatch error.
ErrIncomplete = errors.New("catmsg: incomplete message; may not give result for all inputs")
// ErrNoMatch indicates no translation message matched the given input
// parameters when evaluating a message.
ErrNoMatch = errors.New("catmsg: no translation for inputs")
)
// A Message holds a collection of translations for the same phrase that may
// vary based on the values of substitution arguments.
type Message interface {
// Compile encodes the format string(s) of the message as a string for later
// evaluation.
//
// The first call Compile makes on the encoder must be EncodeMessageType.
// The handle passed to this call may either be a handle returned by
// Register to encode a single custom message, or HandleFirst followed by
// a sequence of calls to EncodeMessage.
//
// Compile must return ErrIncomplete if it is possible for evaluation to
// not match any translation for a given set of formatting parameters.
// For example, selecting a translation based on plural form may not yield
// a match if the form "Other" is not one of the selectors.
//
// Compile may return any other application-specific error. For backwards
// compatibility with package like fmt, which often do not do sanity
// checking of format strings ahead of time, Compile should still make an
// effort to have some sensible fallback in case of an error.
Compile(e *Encoder) error
}
// Compile converts a Message to a data string that can be stored in a Catalog.
// The resulting string can subsequently be decoded by passing to the Execute
// method of a Decoder.
func Compile(tag language.Tag, macros Dictionary, m Message) (data string, err error) {
// TODO: pass macros so they can be used for validation.
v := &Encoder{inBody: true} // encoder for variables
v.root = v
e := &Encoder{root: v, parent: v, tag: tag} // encoder for messages
err = m.Compile(e)
// This package serves te message package, which in turn is meant to be a
// drop-in replacement for fmt. With the fmt package, format strings are
// evaluated lazily and errors are handled by substituting strings in the
// result, rather then returning an error. Dealing with multiple languages
// makes it more important to check errors ahead of time. We chose to be
// consistent and compatible and allow graceful degradation in case of
// errors.
buf := e.buf[stripPrefix(e.buf):]
if len(v.buf) > 0 {
// Prepend variable block.
b := make([]byte, 1+maxVarintBytes+len(v.buf)+len(buf))
b[0] = byte(msgVars)
b = b[:1+encodeUint(b[1:], uint64(len(v.buf)))]
b = append(b, v.buf...)
b = append(b, buf...)
buf = b
}
if err == nil {
err = v.err
}
return string(buf), err
}
// FirstOf is a message type that prints the first message in the sequence that
// resolves to a match for the given substitution arguments.
type FirstOf []Message
// Compile implements Message.
func (s FirstOf) Compile(e *Encoder) error {
e.EncodeMessageType(msgFirst)
err := ErrIncomplete
for i, m := range s {
if err == nil {
return fmt.Errorf("catalog: message argument %d is complete and blocks subsequent messages", i-1)
}
err = e.EncodeMessage(m)
}
return err
}
// Var defines a message that can be substituted for a placeholder of the same
// name. If an expression does not result in a string after evaluation, Name is
// used as the substitution. For example:
// Var{
// Name: "minutes",
// Message: plural.Select(1, "one", "minute"),
// }
// will resolve to minute for singular and minutes for plural forms.
type Var struct {
Name string
Message Message
}
var errIsVar = errors.New("catmsg: variable used as message")
// Compile implements Message.
//
// Note that this method merely registers a variable; it does not create an
// encoded message.
func (v *Var) Compile(e *Encoder) error {
if err := e.addVar(v.Name, v.Message); err != nil {
return err
}
// Using a Var by itself is an error. If it is in a sequence followed by
// other messages referring to it, this error will be ignored.
return errIsVar
}
// Raw is a message consisting of a single format string that is passed as is
// to the Renderer.
//
// Note that a Renderer may still do its own variable substitution.
type Raw string
// Compile implements Message.
func (r Raw) Compile(e *Encoder) (err error) {
e.EncodeMessageType(msgRaw)
// Special case: raw strings don't have a size encoding and so don't use
// EncodeString.
e.buf = append(e.buf, r...)
return nil
}
// String is a message consisting of a single format string which contains
// placeholders that may be substituted with variables.
//
// Variable substitutions are marked with placeholders and a variable name of
// the form ${name}. Any other substitutions such as Go templates or
// printf-style substitutions are left to be done by the Renderer.
//
// When evaluation a string interpolation, a Renderer will receive separate
// calls for each placeholder and interstitial string. For example, for the
// message: "%[1]v ${invites} %[2]v to ${their} party." The sequence of calls
// is:
// d.Render("%[1]v ")
// d.Arg(1)
// d.Render(resultOfInvites)
// d.Render(" %[2]v to ")
// d.Arg(2)
// d.Render(resultOfTheir)
// d.Render(" party.")
// where the messages for "invites" and "their" both use a plural.Select
// referring to the first argument.
//
// Strings may also invoke macros. Macros are essentially variables that can be
// reused. Macros may, for instance, be used to make selections between
// different conjugations of a verb. See the catalog package description for an
// overview of macros.
type String string
// Compile implements Message. It parses the placeholder formats and returns
// any error.
func (s String) Compile(e *Encoder) (err error) {
msg := string(s)
const subStart = "${"
hasHeader := false
p := 0
b := []byte{}
for {
i := strings.Index(msg[p:], subStart)
if i == -1 {
break
}
b = append(b, msg[p:p+i]...)
p += i + len(subStart)
if i = strings.IndexByte(msg[p:], '}'); i == -1 {
b = append(b, "$!(MISSINGBRACE)"...)
err = fmt.Errorf("catmsg: missing '}'")
p = len(msg)
break
}
name := strings.TrimSpace(msg[p : p+i])
if q := strings.IndexByte(name, '('); q == -1 {
if !hasHeader {
hasHeader = true
e.EncodeMessageType(msgString)
}
e.EncodeString(string(b))
e.EncodeSubstitution(name)
b = b[:0]
} else if j := strings.IndexByte(name[q:], ')'); j == -1 {
// TODO: what should the error be?
b = append(b, "$!(MISSINGPAREN)"...)
err = fmt.Errorf("catmsg: missing ')'")
} else if x, sErr := strconv.ParseUint(strings.TrimSpace(name[q+1:q+j]), 10, 32); sErr != nil {
// TODO: handle more than one argument
b = append(b, "$!(BADNUM)"...)
err = fmt.Errorf("catmsg: invalid number %q", strings.TrimSpace(name[q+1:q+j]))
} else {
if !hasHeader {
hasHeader = true
e.EncodeMessageType(msgString)
}
e.EncodeString(string(b))
e.EncodeSubstitution(name[:q], int(x))
b = b[:0]
}
p += i + 1
}
b = append(b, msg[p:]...)
if !hasHeader {
// Simplify string to a raw string.
Raw(string(b)).Compile(e)
} else if len(b) > 0 {
e.EncodeString(string(b))
}
return err
}
// Affix is a message that adds a prefix and suffix to another message.
// This is mostly used add back whitespace to a translation that was stripped
// before sending it out.
type Affix struct {
Message Message
Prefix string
Suffix string
}
// Compile implements Message.
func (a Affix) Compile(e *Encoder) (err error) {
// TODO: consider adding a special message type that just adds a single
// return. This is probably common enough to handle the majority of cases.
// Get some stats first, though.
e.EncodeMessageType(msgAffix)
e.EncodeString(a.Prefix)
e.EncodeString(a.Suffix)
e.EncodeMessage(a.Message)
return nil
}
+407
View File
@@ -0,0 +1,407 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package catmsg
import (
"errors"
"fmt"
"golang.org/x/text/language"
)
// A Renderer renders a Message.
type Renderer interface {
// Render renders the given string. The given string may be interpreted as a
// format string, such as the one used by the fmt package or a template.
Render(s string)
// Arg returns the i-th argument passed to format a message. This method
// should return nil if there is no such argument. Messages need access to
// arguments to allow selecting a message based on linguistic features of
// those arguments.
Arg(i int) interface{}
}
// A Dictionary specifies a source of messages, including variables or macros.
type Dictionary interface {
// Lookup returns the message for the given key. It returns false for ok if
// such a message could not be found.
Lookup(key string) (data string, ok bool)
// TODO: consider returning an interface, instead of a string. This will
// allow implementations to do their own message type decoding.
}
// An Encoder serializes a Message to a string.
type Encoder struct {
// The root encoder is used for storing encoded variables.
root *Encoder
// The parent encoder provides the surrounding scopes for resolving variable
// names.
parent *Encoder
tag language.Tag
// buf holds the encoded message so far. After a message completes encoding,
// the contents of buf, prefixed by the encoded length, are flushed to the
// parent buffer.
buf []byte
// vars is the lookup table of variables in the current scope.
vars []keyVal
err error
inBody bool // if false next call must be EncodeMessageType
}
type keyVal struct {
key string
offset int
}
// Language reports the language for which the encoded message will be stored
// in the Catalog.
func (e *Encoder) Language() language.Tag { return e.tag }
func (e *Encoder) setError(err error) {
if e.root.err == nil {
e.root.err = err
}
}
// EncodeUint encodes x.
func (e *Encoder) EncodeUint(x uint64) {
e.checkInBody()
var buf [maxVarintBytes]byte
n := encodeUint(buf[:], x)
e.buf = append(e.buf, buf[:n]...)
}
// EncodeString encodes s.
func (e *Encoder) EncodeString(s string) {
e.checkInBody()
e.EncodeUint(uint64(len(s)))
e.buf = append(e.buf, s...)
}
// EncodeMessageType marks the current message to be of type h.
//
// It must be the first call of a Message's Compile method.
func (e *Encoder) EncodeMessageType(h Handle) {
if e.inBody {
panic("catmsg: EncodeMessageType not the first method called")
}
e.inBody = true
e.EncodeUint(uint64(h))
}
// EncodeMessage serializes the given message inline at the current position.
func (e *Encoder) EncodeMessage(m Message) error {
e = &Encoder{root: e.root, parent: e, tag: e.tag}
err := m.Compile(e)
if _, ok := m.(*Var); !ok {
e.flushTo(e.parent)
}
return err
}
func (e *Encoder) checkInBody() {
if !e.inBody {
panic("catmsg: expected prior call to EncodeMessageType")
}
}
// stripPrefix indicates the number of prefix bytes that must be stripped to
// turn a single-element sequence into a message that is just this single member
// without its size prefix. If the message can be stripped, b[1:n] contains the
// size prefix.
func stripPrefix(b []byte) (n int) {
if len(b) > 0 && Handle(b[0]) == msgFirst {
x, n, _ := decodeUint(b[1:])
if 1+n+int(x) == len(b) {
return 1 + n
}
}
return 0
}
func (e *Encoder) flushTo(dst *Encoder) {
data := e.buf
p := stripPrefix(data)
if p > 0 {
data = data[1:]
} else {
// Prefix the size.
dst.EncodeUint(uint64(len(data)))
}
dst.buf = append(dst.buf, data...)
}
func (e *Encoder) addVar(key string, m Message) error {
for _, v := range e.parent.vars {
if v.key == key {
err := fmt.Errorf("catmsg: duplicate variable %q", key)
e.setError(err)
return err
}
}
scope := e.parent
// If a variable message is Incomplete, and does not evaluate to a message
// during execution, we fall back to the variable name. We encode this by
// appending the variable name if the message reports it's incomplete.
err := m.Compile(e)
if err != ErrIncomplete {
e.setError(err)
}
switch {
case len(e.buf) == 1 && Handle(e.buf[0]) == msgFirst: // empty sequence
e.buf = e.buf[:0]
e.inBody = false
fallthrough
case len(e.buf) == 0:
// Empty message.
if err := String(key).Compile(e); err != nil {
e.setError(err)
}
case err == ErrIncomplete:
if Handle(e.buf[0]) != msgFirst {
seq := &Encoder{root: e.root, parent: e}
seq.EncodeMessageType(msgFirst)
e.flushTo(seq)
e = seq
}
// e contains a sequence; append the fallback string.
e.EncodeMessage(String(key))
}
// Flush result to variable heap.
offset := len(e.root.buf)
e.flushTo(e.root)
e.buf = e.buf[:0]
// Record variable offset in current scope.
scope.vars = append(scope.vars, keyVal{key: key, offset: offset})
return err
}
const (
substituteVar = iota
substituteMacro
substituteError
)
// EncodeSubstitution inserts a resolved reference to a variable or macro.
//
// This call must be matched with a call to ExecuteSubstitution at decoding
// time.
func (e *Encoder) EncodeSubstitution(name string, arguments ...int) {
if arity := len(arguments); arity > 0 {
// TODO: also resolve macros.
e.EncodeUint(substituteMacro)
e.EncodeString(name)
for _, a := range arguments {
e.EncodeUint(uint64(a))
}
return
}
for scope := e; scope != nil; scope = scope.parent {
for _, v := range scope.vars {
if v.key != name {
continue
}
e.EncodeUint(substituteVar) // TODO: support arity > 0
e.EncodeUint(uint64(v.offset))
return
}
}
// TODO: refer to dictionary-wide scoped variables.
e.EncodeUint(substituteError)
e.EncodeString(name)
e.setError(fmt.Errorf("catmsg: unknown var %q", name))
}
// A Decoder deserializes and evaluates messages that are encoded by an encoder.
type Decoder struct {
tag language.Tag
dst Renderer
macros Dictionary
err error
vars string
data string
macroArg int // TODO: allow more than one argument
}
// NewDecoder returns a new Decoder.
//
// Decoders are designed to be reused for multiple invocations of Execute.
// Only one goroutine may call Execute concurrently.
func NewDecoder(tag language.Tag, r Renderer, macros Dictionary) *Decoder {
return &Decoder{
tag: tag,
dst: r,
macros: macros,
}
}
func (d *Decoder) setError(err error) {
if d.err == nil {
d.err = err
}
}
// Language returns the language in which the message is being rendered.
//
// The destination language may be a child language of the language used for
// encoding. For instance, a decoding language of "pt-PT"" is consistent with an
// encoding language of "pt".
func (d *Decoder) Language() language.Tag { return d.tag }
// Done reports whether there are more bytes to process in this message.
func (d *Decoder) Done() bool { return len(d.data) == 0 }
// Render implements Renderer.
func (d *Decoder) Render(s string) { d.dst.Render(s) }
// Arg implements Renderer.
//
// During evaluation of macros, the argument positions may be mapped to
// arguments that differ from the original call.
func (d *Decoder) Arg(i int) interface{} {
if d.macroArg != 0 {
if i != 1 {
panic("catmsg: only macros with single argument supported")
}
i = d.macroArg
}
return d.dst.Arg(i)
}
// DecodeUint decodes a number that was encoded with EncodeUint and advances the
// position.
func (d *Decoder) DecodeUint() uint64 {
x, n, err := decodeUintString(d.data)
d.data = d.data[n:]
if err != nil {
d.setError(err)
}
return x
}
// DecodeString decodes a string that was encoded with EncodeString and advances
// the position.
func (d *Decoder) DecodeString() string {
size := d.DecodeUint()
s := d.data[:size]
d.data = d.data[size:]
return s
}
// SkipMessage skips the message at the current location and advances the
// position.
func (d *Decoder) SkipMessage() {
n := int(d.DecodeUint())
d.data = d.data[n:]
}
// Execute decodes and evaluates msg.
//
// Only one goroutine may call execute.
func (d *Decoder) Execute(msg string) error {
d.err = nil
if !d.execute(msg) {
return ErrNoMatch
}
return d.err
}
func (d *Decoder) execute(msg string) bool {
saved := d.data
d.data = msg
ok := d.executeMessage()
d.data = saved
return ok
}
// executeMessageFromData is like execute, but also decodes a leading message
// size and clips the given string accordingly.
//
// It reports the number of bytes consumed and whether a message was selected.
func (d *Decoder) executeMessageFromData(s string) (n int, ok bool) {
saved := d.data
d.data = s
size := int(d.DecodeUint())
n = len(s) - len(d.data)
// Sanitize the setting. This allows skipping a size argument for
// RawString and method Done.
d.data = d.data[:size]
ok = d.executeMessage()
n += size - len(d.data)
d.data = saved
return n, ok
}
var errUnknownHandler = errors.New("catmsg: string contains unsupported handler")
// executeMessage reads the handle id, initializes the decoder and executes the
// message. It is assumed that all of d.data[d.p:] is the single message.
func (d *Decoder) executeMessage() bool {
if d.Done() {
// We interpret no data as a valid empty message.
return true
}
handle := d.DecodeUint()
var fn Handler
mutex.Lock()
if int(handle) < len(handlers) {
fn = handlers[handle]
}
mutex.Unlock()
if fn == nil {
d.setError(errUnknownHandler)
d.execute(fmt.Sprintf("\x02$!(UNKNOWNMSGHANDLER=%#x)", handle))
return true
}
return fn(d)
}
// ExecuteMessage decodes and executes the message at the current position.
func (d *Decoder) ExecuteMessage() bool {
n, ok := d.executeMessageFromData(d.data)
d.data = d.data[n:]
return ok
}
// ExecuteSubstitution executes the message corresponding to the substitution
// as encoded by EncodeSubstitution.
func (d *Decoder) ExecuteSubstitution() {
switch x := d.DecodeUint(); x {
case substituteVar:
offset := d.DecodeUint()
d.executeMessageFromData(d.vars[offset:])
case substituteMacro:
name := d.DecodeString()
data, ok := d.macros.Lookup(name)
old := d.macroArg
// TODO: support macros of arity other than 1.
d.macroArg = int(d.DecodeUint())
switch {
case !ok:
// TODO: detect this at creation time.
d.setError(fmt.Errorf("catmsg: undefined macro %q", name))
fallthrough
case !d.execute(data):
d.dst.Render(name) // fall back to macro name.
}
d.macroArg = old
case substituteError:
d.dst.Render(d.DecodeString())
default:
panic("catmsg: unreachable")
}
}
+62
View File
@@ -0,0 +1,62 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package catmsg
// This file implements varint encoding analogous to the one in encoding/binary.
// We need a string version of this function, so we add that here and then add
// the rest for consistency.
import "errors"
var (
errIllegalVarint = errors.New("catmsg: illegal varint")
errVarintTooLarge = errors.New("catmsg: varint too large for uint64")
)
const maxVarintBytes = 10 // maximum length of a varint
// encodeUint encodes x as a variable-sized integer into buf and returns the
// number of bytes written. buf must be at least maxVarintBytes long
func encodeUint(buf []byte, x uint64) (n int) {
for ; x > 127; n++ {
buf[n] = 0x80 | uint8(x&0x7F)
x >>= 7
}
buf[n] = uint8(x)
n++
return n
}
func decodeUintString(s string) (x uint64, size int, err error) {
i := 0
for shift := uint(0); shift < 64; shift += 7 {
if i >= len(s) {
return 0, i, errIllegalVarint
}
b := uint64(s[i])
i++
x |= (b & 0x7F) << shift
if b&0x80 == 0 {
return x, i, nil
}
}
return 0, i, errVarintTooLarge
}
func decodeUint(b []byte) (x uint64, size int, err error) {
i := 0
for shift := uint(0); shift < 64; shift += 7 {
if i >= len(b) {
return 0, i, errIllegalVarint
}
c := uint64(b[i])
i++
x |= (c & 0x7F) << shift
if c&0x80 == 0 {
return x, i, nil
}
}
return 0, i, errVarintTooLarge
}
+41
View File
@@ -0,0 +1,41 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package format contains types for defining language-specific formatting of
// values.
//
// This package is internal now, but will eventually be exposed after the API
// settles.
package format // import "golang.org/x/text/internal/format"
import (
"fmt"
"golang.org/x/text/language"
)
// State represents the printer state passed to custom formatters. It provides
// access to the fmt.State interface and the sentence and language-related
// context.
type State interface {
fmt.State
// Language reports the requested language in which to render a message.
Language() language.Tag
// TODO: consider this and removing rune from the Format method in the
// Formatter interface.
//
// Verb returns the format variant to render, analogous to the types used
// in fmt. Use 'v' for the default or only variant.
// Verb() rune
// TODO: more info:
// - sentence context such as linguistic features passed by the translator.
}
// Formatter is analogous to fmt.Formatter.
type Formatter interface {
Format(state State, verb rune)
}
+358
View File
@@ -0,0 +1,358 @@
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package format
import (
"reflect"
"unicode/utf8"
)
// A Parser parses a format string. The result from the parse are set in the
// struct fields.
type Parser struct {
Verb rune
WidthPresent bool
PrecPresent bool
Minus bool
Plus bool
Sharp bool
Space bool
Zero bool
// For the formats %+v %#v, we set the plusV/sharpV flags
// and clear the plus/sharp flags since %+v and %#v are in effect
// different, flagless formats set at the top level.
PlusV bool
SharpV bool
HasIndex bool
Width int
Prec int // precision
// retain arguments across calls.
Args []interface{}
// retain current argument number across calls
ArgNum int
// reordered records whether the format string used argument reordering.
Reordered bool
// goodArgNum records whether the most recent reordering directive was valid.
goodArgNum bool
// position info
format string
startPos int
endPos int
Status Status
}
// Reset initializes a parser to scan format strings for the given args.
func (p *Parser) Reset(args []interface{}) {
p.Args = args
p.ArgNum = 0
p.startPos = 0
p.Reordered = false
}
// Text returns the part of the format string that was parsed by the last call
// to Scan. It returns the original substitution clause if the current scan
// parsed a substitution.
func (p *Parser) Text() string { return p.format[p.startPos:p.endPos] }
// SetFormat sets a new format string to parse. It does not reset the argument
// count.
func (p *Parser) SetFormat(format string) {
p.format = format
p.startPos = 0
p.endPos = 0
}
// Status indicates the result type of a call to Scan.
type Status int
const (
StatusText Status = iota
StatusSubstitution
StatusBadWidthSubstitution
StatusBadPrecSubstitution
StatusNoVerb
StatusBadArgNum
StatusMissingArg
)
// ClearFlags reset the parser to default behavior.
func (p *Parser) ClearFlags() {
p.WidthPresent = false
p.PrecPresent = false
p.Minus = false
p.Plus = false
p.Sharp = false
p.Space = false
p.Zero = false
p.PlusV = false
p.SharpV = false
p.HasIndex = false
}
// Scan scans the next part of the format string and sets the status to
// indicate whether it scanned a string literal, substitution or error.
func (p *Parser) Scan() bool {
p.Status = StatusText
format := p.format
end := len(format)
if p.endPos >= end {
return false
}
afterIndex := false // previous item in format was an index like [3].
p.startPos = p.endPos
p.goodArgNum = true
i := p.startPos
for i < end && format[i] != '%' {
i++
}
if i > p.startPos {
p.endPos = i
return true
}
// Process one verb
i++
p.Status = StatusSubstitution
// Do we have flags?
p.ClearFlags()
simpleFormat:
for ; i < end; i++ {
c := p.format[i]
switch c {
case '#':
p.Sharp = true
case '0':
p.Zero = !p.Minus // Only allow zero padding to the left.
case '+':
p.Plus = true
case '-':
p.Minus = true
p.Zero = false // Do not pad with zeros to the right.
case ' ':
p.Space = true
default:
// Fast path for common case of ascii lower case simple verbs
// without precision or width or argument indices.
if 'a' <= c && c <= 'z' && p.ArgNum < len(p.Args) {
if c == 'v' {
// Go syntax
p.SharpV = p.Sharp
p.Sharp = false
// Struct-field syntax
p.PlusV = p.Plus
p.Plus = false
}
p.Verb = rune(c)
p.ArgNum++
p.endPos = i + 1
return true
}
// Format is more complex than simple flags and a verb or is malformed.
break simpleFormat
}
}
// Do we have an explicit argument index?
i, afterIndex = p.updateArgNumber(format, i)
// Do we have width?
if i < end && format[i] == '*' {
i++
p.Width, p.WidthPresent = p.intFromArg()
if !p.WidthPresent {
p.Status = StatusBadWidthSubstitution
}
// We have a negative width, so take its value and ensure
// that the minus flag is set
if p.Width < 0 {
p.Width = -p.Width
p.Minus = true
p.Zero = false // Do not pad with zeros to the right.
}
afterIndex = false
} else {
p.Width, p.WidthPresent, i = parsenum(format, i, end)
if afterIndex && p.WidthPresent { // "%[3]2d"
p.goodArgNum = false
}
}
// Do we have precision?
if i+1 < end && format[i] == '.' {
i++
if afterIndex { // "%[3].2d"
p.goodArgNum = false
}
i, afterIndex = p.updateArgNumber(format, i)
if i < end && format[i] == '*' {
i++
p.Prec, p.PrecPresent = p.intFromArg()
// Negative precision arguments don't make sense
if p.Prec < 0 {
p.Prec = 0
p.PrecPresent = false
}
if !p.PrecPresent {
p.Status = StatusBadPrecSubstitution
}
afterIndex = false
} else {
p.Prec, p.PrecPresent, i = parsenum(format, i, end)
if !p.PrecPresent {
p.Prec = 0
p.PrecPresent = true
}
}
}
if !afterIndex {
i, afterIndex = p.updateArgNumber(format, i)
}
p.HasIndex = afterIndex
if i >= end {
p.endPos = i
p.Status = StatusNoVerb
return true
}
verb, w := utf8.DecodeRuneInString(format[i:])
p.endPos = i + w
p.Verb = verb
switch {
case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec.
p.startPos = p.endPos - 1
p.Status = StatusText
case !p.goodArgNum:
p.Status = StatusBadArgNum
case p.ArgNum >= len(p.Args): // No argument left over to print for the current verb.
p.Status = StatusMissingArg
p.ArgNum++
case verb == 'v':
// Go syntax
p.SharpV = p.Sharp
p.Sharp = false
// Struct-field syntax
p.PlusV = p.Plus
p.Plus = false
fallthrough
default:
p.ArgNum++
}
return true
}
// intFromArg gets the ArgNumth element of Args. On return, isInt reports
// whether the argument has integer type.
func (p *Parser) intFromArg() (num int, isInt bool) {
if p.ArgNum < len(p.Args) {
arg := p.Args[p.ArgNum]
num, isInt = arg.(int) // Almost always OK.
if !isInt {
// Work harder.
switch v := reflect.ValueOf(arg); v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n := v.Int()
if int64(int(n)) == n {
num = int(n)
isInt = true
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n := v.Uint()
if int64(n) >= 0 && uint64(int(n)) == n {
num = int(n)
isInt = true
}
default:
// Already 0, false.
}
}
p.ArgNum++
if tooLarge(num) {
num = 0
isInt = false
}
}
return
}
// parseArgNumber returns the value of the bracketed number, minus 1
// (explicit argument numbers are one-indexed but we want zero-indexed).
// The opening bracket is known to be present at format[0].
// The returned values are the index, the number of bytes to consume
// up to the closing paren, if present, and whether the number parsed
// ok. The bytes to consume will be 1 if no closing paren is present.
func parseArgNumber(format string) (index int, wid int, ok bool) {
// There must be at least 3 bytes: [n].
if len(format) < 3 {
return 0, 1, false
}
// Find closing bracket.
for i := 1; i < len(format); i++ {
if format[i] == ']' {
width, ok, newi := parsenum(format, 1, i)
if !ok || newi != i {
return 0, i + 1, false
}
return width - 1, i + 1, true // arg numbers are one-indexed and skip paren.
}
}
return 0, 1, false
}
// updateArgNumber returns the next argument to evaluate, which is either the value of the passed-in
// argNum or the value of the bracketed integer that begins format[i:]. It also returns
// the new value of i, that is, the index of the next byte of the format to process.
func (p *Parser) updateArgNumber(format string, i int) (newi int, found bool) {
if len(format) <= i || format[i] != '[' {
return i, false
}
p.Reordered = true
index, wid, ok := parseArgNumber(format[i:])
if ok && 0 <= index && index < len(p.Args) {
p.ArgNum = index
return i + wid, true
}
p.goodArgNum = false
return i + wid, ok
}
// tooLarge reports whether the magnitude of the integer is
// too large to be used as a formatting width or precision.
func tooLarge(x int) bool {
const max int = 1e6
return x > max || x < -max
}
// parsenum converts ASCII to integer. num is 0 (and isnum is false) if no number present.
func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
if start >= end {
return 0, false, end
}
for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
if tooLarge(num) {
return 0, false, end // Overflow; crazy long number most likely.
}
num = num*10 + int(s[newi]-'0')
isnum = true
}
return
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package internal contains non-exported functionality that are used by
// packages in the text repository.
package internal // import "golang.org/x/text/internal"
import (
"sort"
"golang.org/x/text/language"
)
// SortTags sorts tags in place.
func SortTags(tags []language.Tag) {
sort.Sort(sorter(tags))
}
type sorter []language.Tag
func (s sorter) Len() int {
return len(s)
}
func (s sorter) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
func (s sorter) Less(i, j int) bool {
return s[i].String() < s[j].String()
}
// UniqueTags sorts and filters duplicate tags in place and returns a slice with
// only unique tags.
func UniqueTags(tags []language.Tag) []language.Tag {
if len(tags) <= 1 {
return tags
}
SortTags(tags)
k := 0
for i := 1; i < len(tags); i++ {
if tags[k].String() < tags[i].String() {
k++
tags[k] = tags[i]
}
}
return tags[:k+1]
}
+16
View File
@@ -0,0 +1,16 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package language
// This file contains code common to the maketables.go and the package code.
// AliasType is the type of an alias in AliasMap.
type AliasType int8
const (
Deprecated AliasType = iota
Macro
Legacy
AliasTypeUnknown AliasType = -1
)
+29
View File
@@ -0,0 +1,29 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package language
// CompactCoreInfo is a compact integer with the three core tags encoded.
type CompactCoreInfo uint32
// GetCompactCore generates a uint32 value that is guaranteed to be unique for
// different language, region, and script values.
func GetCompactCore(t Tag) (cci CompactCoreInfo, ok bool) {
if t.LangID > langNoIndexOffset {
return 0, false
}
cci |= CompactCoreInfo(t.LangID) << (8 + 12)
cci |= CompactCoreInfo(t.ScriptID) << 12
cci |= CompactCoreInfo(t.RegionID)
return cci, true
}
// Tag generates a tag from c.
func (c CompactCoreInfo) Tag() Tag {
return Tag{
LangID: Language(c >> 20),
RegionID: Region(c & 0x3ff),
ScriptID: Script(c>>12) & 0xff,
}
}
+61
View File
@@ -0,0 +1,61 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package compact defines a compact representation of language tags.
//
// Common language tags (at least all for which locale information is defined
// in CLDR) are assigned a unique index. Each Tag is associated with such an
// ID for selecting language-related resources (such as translations) as well
// as one for selecting regional defaults (currency, number formatting, etc.)
//
// It may want to export this functionality at some point, but at this point
// this is only available for use within x/text.
package compact // import "golang.org/x/text/internal/language/compact"
import (
"sort"
"strings"
"golang.org/x/text/internal/language"
)
// ID is an integer identifying a single tag.
type ID uint16
func getCoreIndex(t language.Tag) (id ID, ok bool) {
cci, ok := language.GetCompactCore(t)
if !ok {
return 0, false
}
i := sort.Search(len(coreTags), func(i int) bool {
return cci <= coreTags[i]
})
if i == len(coreTags) || coreTags[i] != cci {
return 0, false
}
return ID(i), true
}
// Parent returns the ID of the parent or the root ID if id is already the root.
func (id ID) Parent() ID {
return parents[id]
}
// Tag converts id to an internal language Tag.
func (id ID) Tag() language.Tag {
if int(id) >= len(coreTags) {
return specialTags[int(id)-len(coreTags)]
}
return coreTags[id].Tag()
}
var specialTags []language.Tag
func init() {
tags := strings.Split(specialTagsStr, " ")
specialTags = make([]language.Tag, len(tags))
for i, t := range tags {
specialTags[i] = language.MustParse(t)
}
}
+260
View File
@@ -0,0 +1,260 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run gen.go gen_index.go -output tables.go
//go:generate go run gen_parents.go
package compact
// TODO: Remove above NOTE after:
// - verifying that tables are dropped correctly (most notably matcher tables).
import (
"strings"
"golang.org/x/text/internal/language"
)
// Tag represents a BCP 47 language tag. It is used to specify an instance of a
// specific language or locale. All language tag values are guaranteed to be
// well-formed.
type Tag struct {
// NOTE: exported tags will become part of the public API.
language ID
locale ID
full fullTag // always a language.Tag for now.
}
const _und = 0
type fullTag interface {
IsRoot() bool
Parent() language.Tag
}
// Make a compact Tag from a fully specified internal language Tag.
func Make(t language.Tag) (tag Tag) {
if region := t.TypeForKey("rg"); len(region) == 6 && region[2:] == "zzzz" {
if r, err := language.ParseRegion(region[:2]); err == nil {
tFull := t
t, _ = t.SetTypeForKey("rg", "")
// TODO: should we not consider "va" for the language tag?
var exact1, exact2 bool
tag.language, exact1 = FromTag(t)
t.RegionID = r
tag.locale, exact2 = FromTag(t)
if !exact1 || !exact2 {
tag.full = tFull
}
return tag
}
}
lang, ok := FromTag(t)
tag.language = lang
tag.locale = lang
if !ok {
tag.full = t
}
return tag
}
// Tag returns an internal language Tag version of this tag.
func (t Tag) Tag() language.Tag {
if t.full != nil {
return t.full.(language.Tag)
}
tag := t.language.Tag()
if t.language != t.locale {
loc := t.locale.Tag()
tag, _ = tag.SetTypeForKey("rg", strings.ToLower(loc.RegionID.String())+"zzzz")
}
return tag
}
// IsCompact reports whether this tag is fully defined in terms of ID.
func (t *Tag) IsCompact() bool {
return t.full == nil
}
// MayHaveVariants reports whether a tag may have variants. If it returns false
// it is guaranteed the tag does not have variants.
func (t Tag) MayHaveVariants() bool {
return t.full != nil || int(t.language) >= len(coreTags)
}
// MayHaveExtensions reports whether a tag may have extensions. If it returns
// false it is guaranteed the tag does not have them.
func (t Tag) MayHaveExtensions() bool {
return t.full != nil ||
int(t.language) >= len(coreTags) ||
t.language != t.locale
}
// IsRoot returns true if t is equal to language "und".
func (t Tag) IsRoot() bool {
if t.full != nil {
return t.full.IsRoot()
}
return t.language == _und
}
// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
// specific language are substituted with fields from the parent language.
// The parent for a language may change for newer versions of CLDR.
func (t Tag) Parent() Tag {
if t.full != nil {
return Make(t.full.Parent())
}
if t.language != t.locale {
// Simulate stripping -u-rg-xxxxxx
return Tag{language: t.language, locale: t.language}
}
// TODO: use parent lookup table once cycle from internal package is
// removed. Probably by internalizing the table and declaring this fast
// enough.
// lang := compactID(internal.Parent(uint16(t.language)))
lang, _ := FromTag(t.language.Tag().Parent())
return Tag{language: lang, locale: lang}
}
// returns token t and the rest of the string.
func nextToken(s string) (t, tail string) {
p := strings.Index(s[1:], "-")
if p == -1 {
return s[1:], ""
}
p++
return s[1:p], s[p:]
}
// LanguageID returns an index, where 0 <= index < NumCompactTags, for tags
// for which data exists in the text repository.The index will change over time
// and should not be stored in persistent storage. If t does not match a compact
// index, exact will be false and the compact index will be returned for the
// first match after repeatedly taking the Parent of t.
func LanguageID(t Tag) (id ID, exact bool) {
return t.language, t.full == nil
}
// RegionalID returns the ID for the regional variant of this tag. This index is
// used to indicate region-specific overrides, such as default currency, default
// calendar and week data, default time cycle, and default measurement system
// and unit preferences.
//
// For instance, the tag en-GB-u-rg-uszzzz specifies British English with US
// settings for currency, number formatting, etc. The CompactIndex for this tag
// will be that for en-GB, while the RegionalID will be the one corresponding to
// en-US.
func RegionalID(t Tag) (id ID, exact bool) {
return t.locale, t.full == nil
}
// LanguageTag returns t stripped of regional variant indicators.
//
// At the moment this means it is stripped of a regional and variant subtag "rg"
// and "va" in the "u" extension.
func (t Tag) LanguageTag() Tag {
if t.full == nil {
return Tag{language: t.language, locale: t.language}
}
tt := t.Tag()
tt.SetTypeForKey("rg", "")
tt.SetTypeForKey("va", "")
return Make(tt)
}
// RegionalTag returns the regional variant of the tag.
//
// At the moment this means that the region is set from the regional subtag
// "rg" in the "u" extension.
func (t Tag) RegionalTag() Tag {
rt := Tag{language: t.locale, locale: t.locale}
if t.full == nil {
return rt
}
b := language.Builder{}
tag := t.Tag()
// tag, _ = tag.SetTypeForKey("rg", "")
b.SetTag(t.locale.Tag())
if v := tag.Variants(); v != "" {
for _, v := range strings.Split(v, "-") {
b.AddVariant(v)
}
}
for _, e := range tag.Extensions() {
b.AddExt(e)
}
return t
}
// FromTag reports closest matching ID for an internal language Tag.
func FromTag(t language.Tag) (id ID, exact bool) {
// TODO: perhaps give more frequent tags a lower index.
// TODO: we could make the indexes stable. This will excluded some
// possibilities for optimization, so don't do this quite yet.
exact = true
b, s, r := t.Raw()
if t.HasString() {
if t.IsPrivateUse() {
// We have no entries for user-defined tags.
return 0, false
}
hasExtra := false
if t.HasVariants() {
if t.HasExtensions() {
build := language.Builder{}
build.SetTag(language.Tag{LangID: b, ScriptID: s, RegionID: r})
build.AddVariant(t.Variants())
exact = false
t = build.Make()
}
hasExtra = true
} else if _, ok := t.Extension('u'); ok {
// TODO: va may mean something else. Consider not considering it.
// Strip all but the 'va' entry.
old := t
variant := t.TypeForKey("va")
t = language.Tag{LangID: b, ScriptID: s, RegionID: r}
if variant != "" {
t, _ = t.SetTypeForKey("va", variant)
hasExtra = true
}
exact = old == t
} else {
exact = false
}
if hasExtra {
// We have some variants.
for i, s := range specialTags {
if s == t {
return ID(i + len(coreTags)), exact
}
}
exact = false
}
}
if x, ok := getCoreIndex(t); ok {
return x, exact
}
exact = false
if r != 0 && s == 0 {
// Deal with cases where an extra script is inserted for the region.
t, _ := t.Maximize()
if x, ok := getCoreIndex(t); ok {
return x, exact
}
}
for t = t.Parent(); t != root; t = t.Parent() {
// No variants specified: just compare core components.
// The key has the form lllssrrr, where l, s, and r are nibbles for
// respectively the langID, scriptID, and regionID.
if x, ok := getCoreIndex(t); ok {
return x, exact
}
}
return 0, exact
}
var root = language.Tag{}
+120
View File
@@ -0,0 +1,120 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package compact
// parents maps a compact index of a tag to the compact index of the parent of
// this tag.
var parents = []ID{ // 775 elements
// Entry 0 - 3F
0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0004, 0x0000, 0x0006,
0x0000, 0x0008, 0x0000, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a,
0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x0000,
0x0000, 0x0028, 0x0000, 0x002a, 0x0000, 0x002c, 0x0000, 0x0000,
0x002f, 0x002e, 0x002e, 0x0000, 0x0033, 0x0000, 0x0035, 0x0000,
0x0037, 0x0000, 0x0039, 0x0000, 0x003b, 0x0000, 0x0000, 0x003e,
// Entry 40 - 7F
0x0000, 0x0040, 0x0040, 0x0000, 0x0043, 0x0043, 0x0000, 0x0046,
0x0000, 0x0048, 0x0000, 0x0000, 0x004b, 0x004a, 0x004a, 0x0000,
0x004f, 0x004f, 0x004f, 0x004f, 0x0000, 0x0054, 0x0054, 0x0000,
0x0057, 0x0000, 0x0059, 0x0000, 0x005b, 0x0000, 0x005d, 0x005d,
0x0000, 0x0060, 0x0000, 0x0062, 0x0000, 0x0064, 0x0000, 0x0066,
0x0066, 0x0000, 0x0069, 0x0000, 0x006b, 0x006b, 0x006b, 0x006b,
0x006b, 0x006b, 0x006b, 0x0000, 0x0073, 0x0000, 0x0075, 0x0000,
0x0077, 0x0000, 0x0000, 0x007a, 0x0000, 0x007c, 0x0000, 0x007e,
// Entry 80 - BF
0x0000, 0x0080, 0x0080, 0x0000, 0x0083, 0x0083, 0x0000, 0x0086,
0x0087, 0x0087, 0x0087, 0x0086, 0x0088, 0x0087, 0x0087, 0x0087,
0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0088,
0x0087, 0x0087, 0x0087, 0x0087, 0x0088, 0x0087, 0x0088, 0x0087,
0x0087, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
0x0087, 0x0087, 0x0087, 0x0086, 0x0087, 0x0087, 0x0087, 0x0087,
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0087, 0x0086,
// Entry C0 - FF
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0088, 0x0087,
0x0087, 0x0088, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0086, 0x0086, 0x0087,
0x0087, 0x0086, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0000,
0x00ef, 0x0000, 0x00f1, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2,
0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f1, 0x00f2, 0x00f1, 0x00f1,
// Entry 100 - 13F
0x00f2, 0x00f2, 0x00f1, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f1,
0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x00f2, 0x0000, 0x010e,
0x0000, 0x0110, 0x0000, 0x0112, 0x0000, 0x0114, 0x0114, 0x0000,
0x0117, 0x0117, 0x0117, 0x0117, 0x0000, 0x011c, 0x0000, 0x011e,
0x0000, 0x0120, 0x0120, 0x0000, 0x0123, 0x0123, 0x0123, 0x0123,
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
// Entry 140 - 17F
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123, 0x0123,
0x0123, 0x0123, 0x0000, 0x0152, 0x0000, 0x0154, 0x0000, 0x0156,
0x0000, 0x0158, 0x0000, 0x015a, 0x0000, 0x015c, 0x015c, 0x015c,
0x0000, 0x0160, 0x0000, 0x0000, 0x0163, 0x0000, 0x0165, 0x0000,
0x0167, 0x0167, 0x0167, 0x0000, 0x016b, 0x0000, 0x016d, 0x0000,
0x016f, 0x0000, 0x0171, 0x0171, 0x0000, 0x0174, 0x0000, 0x0176,
0x0000, 0x0178, 0x0000, 0x017a, 0x0000, 0x017c, 0x0000, 0x017e,
// Entry 180 - 1BF
0x0000, 0x0000, 0x0000, 0x0182, 0x0000, 0x0184, 0x0184, 0x0184,
0x0184, 0x0000, 0x0000, 0x0000, 0x018b, 0x0000, 0x0000, 0x018e,
0x0000, 0x0000, 0x0191, 0x0000, 0x0000, 0x0000, 0x0195, 0x0000,
0x0197, 0x0000, 0x0000, 0x019a, 0x0000, 0x0000, 0x019d, 0x0000,
0x019f, 0x0000, 0x01a1, 0x0000, 0x01a3, 0x0000, 0x01a5, 0x0000,
0x01a7, 0x0000, 0x01a9, 0x0000, 0x01ab, 0x0000, 0x01ad, 0x0000,
0x01af, 0x0000, 0x01b1, 0x01b1, 0x0000, 0x01b4, 0x0000, 0x01b6,
0x0000, 0x01b8, 0x0000, 0x01ba, 0x0000, 0x01bc, 0x0000, 0x0000,
// Entry 1C0 - 1FF
0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x0000, 0x01c5, 0x0000,
0x01c7, 0x0000, 0x01c9, 0x0000, 0x01cb, 0x01cb, 0x01cb, 0x01cb,
0x0000, 0x01d0, 0x0000, 0x01d2, 0x01d2, 0x0000, 0x01d5, 0x0000,
0x01d7, 0x0000, 0x01d9, 0x0000, 0x01db, 0x0000, 0x01dd, 0x0000,
0x01df, 0x01df, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6,
0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x0000, 0x01ee,
0x0000, 0x01f0, 0x0000, 0x0000, 0x01f3, 0x0000, 0x01f5, 0x01f5,
0x01f5, 0x0000, 0x01f9, 0x0000, 0x01fb, 0x0000, 0x01fd, 0x0000,
// Entry 200 - 23F
0x01ff, 0x0000, 0x0000, 0x0202, 0x0000, 0x0204, 0x0204, 0x0000,
0x0207, 0x0000, 0x0209, 0x0209, 0x0000, 0x020c, 0x020c, 0x0000,
0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x020f, 0x0000,
0x0217, 0x0000, 0x0219, 0x0000, 0x021b, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0221, 0x0000, 0x0000, 0x0224, 0x0000, 0x0226,
0x0226, 0x0000, 0x0229, 0x0000, 0x022b, 0x022b, 0x0000, 0x0000,
0x022f, 0x022e, 0x022e, 0x0000, 0x0000, 0x0234, 0x0000, 0x0236,
0x0000, 0x0238, 0x0000, 0x0244, 0x023a, 0x0244, 0x0244, 0x0244,
// Entry 240 - 27F
0x0244, 0x0244, 0x0244, 0x0244, 0x023a, 0x0244, 0x0244, 0x0000,
0x0247, 0x0247, 0x0247, 0x0000, 0x024b, 0x0000, 0x024d, 0x0000,
0x024f, 0x024f, 0x0000, 0x0252, 0x0000, 0x0254, 0x0254, 0x0254,
0x0254, 0x0254, 0x0254, 0x0000, 0x025b, 0x0000, 0x025d, 0x0000,
0x025f, 0x0000, 0x0261, 0x0000, 0x0263, 0x0000, 0x0265, 0x0000,
0x0000, 0x0268, 0x0268, 0x0268, 0x0000, 0x026c, 0x0000, 0x026e,
0x0000, 0x0270, 0x0000, 0x0000, 0x0000, 0x0274, 0x0273, 0x0273,
0x0000, 0x0278, 0x0000, 0x027a, 0x0000, 0x027c, 0x0000, 0x0000,
// Entry 280 - 2BF
0x0000, 0x0000, 0x0281, 0x0000, 0x0000, 0x0284, 0x0000, 0x0286,
0x0286, 0x0286, 0x0286, 0x0000, 0x028b, 0x028b, 0x028b, 0x0000,
0x028f, 0x028f, 0x028f, 0x028f, 0x028f, 0x0000, 0x0295, 0x0295,
0x0295, 0x0295, 0x0000, 0x0000, 0x0000, 0x0000, 0x029d, 0x029d,
0x029d, 0x0000, 0x02a1, 0x02a1, 0x02a1, 0x02a1, 0x0000, 0x0000,
0x02a7, 0x02a7, 0x02a7, 0x02a7, 0x0000, 0x02ac, 0x0000, 0x02ae,
0x02ae, 0x0000, 0x02b1, 0x0000, 0x02b3, 0x0000, 0x02b5, 0x02b5,
0x0000, 0x0000, 0x02b9, 0x0000, 0x0000, 0x0000, 0x02bd, 0x0000,
// Entry 2C0 - 2FF
0x02bf, 0x02bf, 0x0000, 0x0000, 0x02c3, 0x0000, 0x02c5, 0x0000,
0x02c7, 0x0000, 0x02c9, 0x0000, 0x02cb, 0x0000, 0x02cd, 0x02cd,
0x0000, 0x0000, 0x02d1, 0x0000, 0x02d3, 0x02d0, 0x02d0, 0x0000,
0x0000, 0x02d8, 0x02d7, 0x02d7, 0x0000, 0x0000, 0x02dd, 0x0000,
0x02df, 0x0000, 0x02e1, 0x0000, 0x0000, 0x02e4, 0x0000, 0x02e6,
0x0000, 0x0000, 0x02e9, 0x0000, 0x02eb, 0x0000, 0x02ed, 0x0000,
0x02ef, 0x02ef, 0x0000, 0x0000, 0x02f3, 0x02f2, 0x02f2, 0x0000,
0x02f7, 0x0000, 0x02f9, 0x02f9, 0x02f9, 0x02f9, 0x02f9, 0x0000,
// Entry 300 - 33F
0x02ff, 0x0300, 0x02ff, 0x0000, 0x0303, 0x0051, 0x00e6,
} // Size: 1574 bytes
// Total table size 1574 bytes (1KiB); checksum: 895AAF0B
File diff suppressed because it is too large Load Diff
+91
View File
@@ -0,0 +1,91 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package compact
var (
und = Tag{}
Und Tag = Tag{}
Afrikaans Tag = Tag{language: afIndex, locale: afIndex}
Amharic Tag = Tag{language: amIndex, locale: amIndex}
Arabic Tag = Tag{language: arIndex, locale: arIndex}
ModernStandardArabic Tag = Tag{language: ar001Index, locale: ar001Index}
Azerbaijani Tag = Tag{language: azIndex, locale: azIndex}
Bulgarian Tag = Tag{language: bgIndex, locale: bgIndex}
Bengali Tag = Tag{language: bnIndex, locale: bnIndex}
Catalan Tag = Tag{language: caIndex, locale: caIndex}
Czech Tag = Tag{language: csIndex, locale: csIndex}
Danish Tag = Tag{language: daIndex, locale: daIndex}
German Tag = Tag{language: deIndex, locale: deIndex}
Greek Tag = Tag{language: elIndex, locale: elIndex}
English Tag = Tag{language: enIndex, locale: enIndex}
AmericanEnglish Tag = Tag{language: enUSIndex, locale: enUSIndex}
BritishEnglish Tag = Tag{language: enGBIndex, locale: enGBIndex}
Spanish Tag = Tag{language: esIndex, locale: esIndex}
EuropeanSpanish Tag = Tag{language: esESIndex, locale: esESIndex}
LatinAmericanSpanish Tag = Tag{language: es419Index, locale: es419Index}
Estonian Tag = Tag{language: etIndex, locale: etIndex}
Persian Tag = Tag{language: faIndex, locale: faIndex}
Finnish Tag = Tag{language: fiIndex, locale: fiIndex}
Filipino Tag = Tag{language: filIndex, locale: filIndex}
French Tag = Tag{language: frIndex, locale: frIndex}
CanadianFrench Tag = Tag{language: frCAIndex, locale: frCAIndex}
Gujarati Tag = Tag{language: guIndex, locale: guIndex}
Hebrew Tag = Tag{language: heIndex, locale: heIndex}
Hindi Tag = Tag{language: hiIndex, locale: hiIndex}
Croatian Tag = Tag{language: hrIndex, locale: hrIndex}
Hungarian Tag = Tag{language: huIndex, locale: huIndex}
Armenian Tag = Tag{language: hyIndex, locale: hyIndex}
Indonesian Tag = Tag{language: idIndex, locale: idIndex}
Icelandic Tag = Tag{language: isIndex, locale: isIndex}
Italian Tag = Tag{language: itIndex, locale: itIndex}
Japanese Tag = Tag{language: jaIndex, locale: jaIndex}
Georgian Tag = Tag{language: kaIndex, locale: kaIndex}
Kazakh Tag = Tag{language: kkIndex, locale: kkIndex}
Khmer Tag = Tag{language: kmIndex, locale: kmIndex}
Kannada Tag = Tag{language: knIndex, locale: knIndex}
Korean Tag = Tag{language: koIndex, locale: koIndex}
Kirghiz Tag = Tag{language: kyIndex, locale: kyIndex}
Lao Tag = Tag{language: loIndex, locale: loIndex}
Lithuanian Tag = Tag{language: ltIndex, locale: ltIndex}
Latvian Tag = Tag{language: lvIndex, locale: lvIndex}
Macedonian Tag = Tag{language: mkIndex, locale: mkIndex}
Malayalam Tag = Tag{language: mlIndex, locale: mlIndex}
Mongolian Tag = Tag{language: mnIndex, locale: mnIndex}
Marathi Tag = Tag{language: mrIndex, locale: mrIndex}
Malay Tag = Tag{language: msIndex, locale: msIndex}
Burmese Tag = Tag{language: myIndex, locale: myIndex}
Nepali Tag = Tag{language: neIndex, locale: neIndex}
Dutch Tag = Tag{language: nlIndex, locale: nlIndex}
Norwegian Tag = Tag{language: noIndex, locale: noIndex}
Punjabi Tag = Tag{language: paIndex, locale: paIndex}
Polish Tag = Tag{language: plIndex, locale: plIndex}
Portuguese Tag = Tag{language: ptIndex, locale: ptIndex}
BrazilianPortuguese Tag = Tag{language: ptBRIndex, locale: ptBRIndex}
EuropeanPortuguese Tag = Tag{language: ptPTIndex, locale: ptPTIndex}
Romanian Tag = Tag{language: roIndex, locale: roIndex}
Russian Tag = Tag{language: ruIndex, locale: ruIndex}
Sinhala Tag = Tag{language: siIndex, locale: siIndex}
Slovak Tag = Tag{language: skIndex, locale: skIndex}
Slovenian Tag = Tag{language: slIndex, locale: slIndex}
Albanian Tag = Tag{language: sqIndex, locale: sqIndex}
Serbian Tag = Tag{language: srIndex, locale: srIndex}
SerbianLatin Tag = Tag{language: srLatnIndex, locale: srLatnIndex}
Swedish Tag = Tag{language: svIndex, locale: svIndex}
Swahili Tag = Tag{language: swIndex, locale: swIndex}
Tamil Tag = Tag{language: taIndex, locale: taIndex}
Telugu Tag = Tag{language: teIndex, locale: teIndex}
Thai Tag = Tag{language: thIndex, locale: thIndex}
Turkish Tag = Tag{language: trIndex, locale: trIndex}
Ukrainian Tag = Tag{language: ukIndex, locale: ukIndex}
Urdu Tag = Tag{language: urIndex, locale: urIndex}
Uzbek Tag = Tag{language: uzIndex, locale: uzIndex}
Vietnamese Tag = Tag{language: viIndex, locale: viIndex}
Chinese Tag = Tag{language: zhIndex, locale: zhIndex}
SimplifiedChinese Tag = Tag{language: zhHansIndex, locale: zhHansIndex}
TraditionalChinese Tag = Tag{language: zhHantIndex, locale: zhHantIndex}
Zulu Tag = Tag{language: zuIndex, locale: zuIndex}
)
+167
View File
@@ -0,0 +1,167 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package language
import (
"sort"
"strings"
)
// A Builder allows constructing a Tag from individual components.
// Its main user is Compose in the top-level language package.
type Builder struct {
Tag Tag
private string // the x extension
variants []string
extensions []string
}
// Make returns a new Tag from the current settings.
func (b *Builder) Make() Tag {
t := b.Tag
if len(b.extensions) > 0 || len(b.variants) > 0 {
sort.Sort(sortVariants(b.variants))
sort.Strings(b.extensions)
if b.private != "" {
b.extensions = append(b.extensions, b.private)
}
n := maxCoreSize + tokenLen(b.variants...) + tokenLen(b.extensions...)
buf := make([]byte, n)
p := t.genCoreBytes(buf)
t.pVariant = byte(p)
p += appendTokens(buf[p:], b.variants...)
t.pExt = uint16(p)
p += appendTokens(buf[p:], b.extensions...)
t.str = string(buf[:p])
// We may not always need to remake the string, but when or when not
// to do so is rather tricky.
scan := makeScanner(buf[:p])
t, _ = parse(&scan, "")
return t
} else if b.private != "" {
t.str = b.private
t.RemakeString()
}
return t
}
// SetTag copies all the settings from a given Tag. Any previously set values
// are discarded.
func (b *Builder) SetTag(t Tag) {
b.Tag.LangID = t.LangID
b.Tag.RegionID = t.RegionID
b.Tag.ScriptID = t.ScriptID
// TODO: optimize
b.variants = b.variants[:0]
if variants := t.Variants(); variants != "" {
for _, vr := range strings.Split(variants[1:], "-") {
b.variants = append(b.variants, vr)
}
}
b.extensions, b.private = b.extensions[:0], ""
for _, e := range t.Extensions() {
b.AddExt(e)
}
}
// AddExt adds extension e to the tag. e must be a valid extension as returned
// by Tag.Extension. If the extension already exists, it will be discarded,
// except for a -u extension, where non-existing key-type pairs will added.
func (b *Builder) AddExt(e string) {
if e[0] == 'x' {
if b.private == "" {
b.private = e
}
return
}
for i, s := range b.extensions {
if s[0] == e[0] {
if e[0] == 'u' {
b.extensions[i] += e[1:]
}
return
}
}
b.extensions = append(b.extensions, e)
}
// SetExt sets the extension e to the tag. e must be a valid extension as
// returned by Tag.Extension. If the extension already exists, it will be
// overwritten, except for a -u extension, where the individual key-type pairs
// will be set.
func (b *Builder) SetExt(e string) {
if e[0] == 'x' {
b.private = e
return
}
for i, s := range b.extensions {
if s[0] == e[0] {
if e[0] == 'u' {
b.extensions[i] = e + s[1:]
} else {
b.extensions[i] = e
}
return
}
}
b.extensions = append(b.extensions, e)
}
// AddVariant adds any number of variants.
func (b *Builder) AddVariant(v ...string) {
for _, v := range v {
if v != "" {
b.variants = append(b.variants, v)
}
}
}
// ClearVariants removes any variants previously added, including those
// copied from a Tag in SetTag.
func (b *Builder) ClearVariants() {
b.variants = b.variants[:0]
}
// ClearExtensions removes any extensions previously added, including those
// copied from a Tag in SetTag.
func (b *Builder) ClearExtensions() {
b.private = ""
b.extensions = b.extensions[:0]
}
func tokenLen(token ...string) (n int) {
for _, t := range token {
n += len(t) + 1
}
return
}
func appendTokens(b []byte, token ...string) int {
p := 0
for _, t := range token {
b[p] = '-'
copy(b[p+1:], t)
p += 1 + len(t)
}
return p
}
type sortVariants []string
func (s sortVariants) Len() int {
return len(s)
}
func (s sortVariants) Swap(i, j int) {
s[j], s[i] = s[i], s[j]
}
func (s sortVariants) Less(i, j int) bool {
return variantIndex[s[i]] < variantIndex[s[j]]
}
+28
View File
@@ -0,0 +1,28 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package language
// BaseLanguages returns the list of all supported base languages. It generates
// the list by traversing the internal structures.
func BaseLanguages() []Language {
base := make([]Language, 0, NumLanguages)
for i := 0; i < langNoIndexOffset; i++ {
// We included "und" already for the value 0.
if i != nonCanonicalUnd {
base = append(base, Language(i))
}
}
i := langNoIndexOffset
for _, v := range langNoIndex {
for k := 0; k < 8; k++ {
if v&1 == 1 {
base = append(base, Language(i))
}
v >>= 1
i++
}
}
return base
}
+596
View File
@@ -0,0 +1,596 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run gen.go gen_common.go -output tables.go
package language // import "golang.org/x/text/internal/language"
// TODO: Remove above NOTE after:
// - verifying that tables are dropped correctly (most notably matcher tables).
import (
"errors"
"fmt"
"strings"
)
const (
// maxCoreSize is the maximum size of a BCP 47 tag without variants and
// extensions. Equals max lang (3) + script (4) + max reg (3) + 2 dashes.
maxCoreSize = 12
// max99thPercentileSize is a somewhat arbitrary buffer size that presumably
// is large enough to hold at least 99% of the BCP 47 tags.
max99thPercentileSize = 32
// maxSimpleUExtensionSize is the maximum size of a -u extension with one
// key-type pair. Equals len("-u-") + key (2) + dash + max value (8).
maxSimpleUExtensionSize = 14
)
// Tag represents a BCP 47 language tag. It is used to specify an instance of a
// specific language or locale. All language tag values are guaranteed to be
// well-formed. The zero value of Tag is Und.
type Tag struct {
// TODO: the following fields have the form TagTypeID. This name is chosen
// to allow refactoring the public package without conflicting with its
// Base, Script, and Region methods. Once the transition is fully completed
// the ID can be stripped from the name.
LangID Language
RegionID Region
// TODO: we will soon run out of positions for ScriptID. Idea: instead of
// storing lang, region, and ScriptID codes, store only the compact index and
// have a lookup table from this code to its expansion. This greatly speeds
// up table lookup, speed up common variant cases.
// This will also immediately free up 3 extra bytes. Also, the pVariant
// field can now be moved to the lookup table, as the compact index uniquely
// determines the offset of a possible variant.
ScriptID Script
pVariant byte // offset in str, includes preceding '-'
pExt uint16 // offset of first extension, includes preceding '-'
// str is the string representation of the Tag. It will only be used if the
// tag has variants or extensions.
str string
}
// Make is a convenience wrapper for Parse that omits the error.
// In case of an error, a sensible default is returned.
func Make(s string) Tag {
t, _ := Parse(s)
return t
}
// Raw returns the raw base language, script and region, without making an
// attempt to infer their values.
// TODO: consider removing
func (t Tag) Raw() (b Language, s Script, r Region) {
return t.LangID, t.ScriptID, t.RegionID
}
// equalTags compares language, script and region subtags only.
func (t Tag) equalTags(a Tag) bool {
return t.LangID == a.LangID && t.ScriptID == a.ScriptID && t.RegionID == a.RegionID
}
// IsRoot returns true if t is equal to language "und".
func (t Tag) IsRoot() bool {
if int(t.pVariant) < len(t.str) {
return false
}
return t.equalTags(Und)
}
// IsPrivateUse reports whether the Tag consists solely of an IsPrivateUse use
// tag.
func (t Tag) IsPrivateUse() bool {
return t.str != "" && t.pVariant == 0
}
// RemakeString is used to update t.str in case lang, script or region changed.
// It is assumed that pExt and pVariant still point to the start of the
// respective parts.
func (t *Tag) RemakeString() {
if t.str == "" {
return
}
extra := t.str[t.pVariant:]
if t.pVariant > 0 {
extra = extra[1:]
}
if t.equalTags(Und) && strings.HasPrefix(extra, "x-") {
t.str = extra
t.pVariant = 0
t.pExt = 0
return
}
var buf [max99thPercentileSize]byte // avoid extra memory allocation in most cases.
b := buf[:t.genCoreBytes(buf[:])]
if extra != "" {
diff := len(b) - int(t.pVariant)
b = append(b, '-')
b = append(b, extra...)
t.pVariant = uint8(int(t.pVariant) + diff)
t.pExt = uint16(int(t.pExt) + diff)
} else {
t.pVariant = uint8(len(b))
t.pExt = uint16(len(b))
}
t.str = string(b)
}
// genCoreBytes writes a string for the base languages, script and region tags
// to the given buffer and returns the number of bytes written. It will never
// write more than maxCoreSize bytes.
func (t *Tag) genCoreBytes(buf []byte) int {
n := t.LangID.StringToBuf(buf[:])
if t.ScriptID != 0 {
n += copy(buf[n:], "-")
n += copy(buf[n:], t.ScriptID.String())
}
if t.RegionID != 0 {
n += copy(buf[n:], "-")
n += copy(buf[n:], t.RegionID.String())
}
return n
}
// String returns the canonical string representation of the language tag.
func (t Tag) String() string {
if t.str != "" {
return t.str
}
if t.ScriptID == 0 && t.RegionID == 0 {
return t.LangID.String()
}
buf := [maxCoreSize]byte{}
return string(buf[:t.genCoreBytes(buf[:])])
}
// MarshalText implements encoding.TextMarshaler.
func (t Tag) MarshalText() (text []byte, err error) {
if t.str != "" {
text = append(text, t.str...)
} else if t.ScriptID == 0 && t.RegionID == 0 {
text = append(text, t.LangID.String()...)
} else {
buf := [maxCoreSize]byte{}
text = buf[:t.genCoreBytes(buf[:])]
}
return text, nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (t *Tag) UnmarshalText(text []byte) error {
tag, err := Parse(string(text))
*t = tag
return err
}
// Variants returns the part of the tag holding all variants or the empty string
// if there are no variants defined.
func (t Tag) Variants() string {
if t.pVariant == 0 {
return ""
}
return t.str[t.pVariant:t.pExt]
}
// VariantOrPrivateUseTags returns variants or private use tags.
func (t Tag) VariantOrPrivateUseTags() string {
if t.pExt > 0 {
return t.str[t.pVariant:t.pExt]
}
return t.str[t.pVariant:]
}
// HasString reports whether this tag defines more than just the raw
// components.
func (t Tag) HasString() bool {
return t.str != ""
}
// Parent returns the CLDR parent of t. In CLDR, missing fields in data for a
// specific language are substituted with fields from the parent language.
// The parent for a language may change for newer versions of CLDR.
func (t Tag) Parent() Tag {
if t.str != "" {
// Strip the variants and extensions.
b, s, r := t.Raw()
t = Tag{LangID: b, ScriptID: s, RegionID: r}
if t.RegionID == 0 && t.ScriptID != 0 && t.LangID != 0 {
base, _ := addTags(Tag{LangID: t.LangID})
if base.ScriptID == t.ScriptID {
return Tag{LangID: t.LangID}
}
}
return t
}
if t.LangID != 0 {
if t.RegionID != 0 {
maxScript := t.ScriptID
if maxScript == 0 {
max, _ := addTags(t)
maxScript = max.ScriptID
}
for i := range parents {
if Language(parents[i].lang) == t.LangID && Script(parents[i].maxScript) == maxScript {
for _, r := range parents[i].fromRegion {
if Region(r) == t.RegionID {
return Tag{
LangID: t.LangID,
ScriptID: Script(parents[i].script),
RegionID: Region(parents[i].toRegion),
}
}
}
}
}
// Strip the script if it is the default one.
base, _ := addTags(Tag{LangID: t.LangID})
if base.ScriptID != maxScript {
return Tag{LangID: t.LangID, ScriptID: maxScript}
}
return Tag{LangID: t.LangID}
} else if t.ScriptID != 0 {
// The parent for an base-script pair with a non-default script is
// "und" instead of the base language.
base, _ := addTags(Tag{LangID: t.LangID})
if base.ScriptID != t.ScriptID {
return Und
}
return Tag{LangID: t.LangID}
}
}
return Und
}
// ParseExtension parses s as an extension and returns it on success.
func ParseExtension(s string) (ext string, err error) {
scan := makeScannerString(s)
var end int
if n := len(scan.token); n != 1 {
return "", ErrSyntax
}
scan.toLower(0, len(scan.b))
end = parseExtension(&scan)
if end != len(s) {
return "", ErrSyntax
}
return string(scan.b), nil
}
// HasVariants reports whether t has variants.
func (t Tag) HasVariants() bool {
return uint16(t.pVariant) < t.pExt
}
// HasExtensions reports whether t has extensions.
func (t Tag) HasExtensions() bool {
return int(t.pExt) < len(t.str)
}
// Extension returns the extension of type x for tag t. It will return
// false for ok if t does not have the requested extension. The returned
// extension will be invalid in this case.
func (t Tag) Extension(x byte) (ext string, ok bool) {
for i := int(t.pExt); i < len(t.str)-1; {
var ext string
i, ext = getExtension(t.str, i)
if ext[0] == x {
return ext, true
}
}
return "", false
}
// Extensions returns all extensions of t.
func (t Tag) Extensions() []string {
e := []string{}
for i := int(t.pExt); i < len(t.str)-1; {
var ext string
i, ext = getExtension(t.str, i)
e = append(e, ext)
}
return e
}
// TypeForKey returns the type associated with the given key, where key and type
// are of the allowed values defined for the Unicode locale extension ('u') in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
// TypeForKey will traverse the inheritance chain to get the correct value.
func (t Tag) TypeForKey(key string) string {
if start, end, _ := t.findTypeForKey(key); end != start {
return t.str[start:end]
}
return ""
}
var (
errPrivateUse = errors.New("cannot set a key on a private use tag")
errInvalidArguments = errors.New("invalid key or type")
)
// SetTypeForKey returns a new Tag with the key set to type, where key and type
// are of the allowed values defined for the Unicode locale extension ('u') in
// https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers.
// An empty value removes an existing pair with the same key.
func (t Tag) SetTypeForKey(key, value string) (Tag, error) {
if t.IsPrivateUse() {
return t, errPrivateUse
}
if len(key) != 2 {
return t, errInvalidArguments
}
// Remove the setting if value is "".
if value == "" {
start, end, _ := t.findTypeForKey(key)
if start != end {
// Remove key tag and leading '-'.
start -= 4
// Remove a possible empty extension.
if (end == len(t.str) || t.str[end+2] == '-') && t.str[start-2] == '-' {
start -= 2
}
if start == int(t.pVariant) && end == len(t.str) {
t.str = ""
t.pVariant, t.pExt = 0, 0
} else {
t.str = fmt.Sprintf("%s%s", t.str[:start], t.str[end:])
}
}
return t, nil
}
if len(value) < 3 || len(value) > 8 {
return t, errInvalidArguments
}
var (
buf [maxCoreSize + maxSimpleUExtensionSize]byte
uStart int // start of the -u extension.
)
// Generate the tag string if needed.
if t.str == "" {
uStart = t.genCoreBytes(buf[:])
buf[uStart] = '-'
uStart++
}
// Create new key-type pair and parse it to verify.
b := buf[uStart:]
copy(b, "u-")
copy(b[2:], key)
b[4] = '-'
b = b[:5+copy(b[5:], value)]
scan := makeScanner(b)
if parseExtensions(&scan); scan.err != nil {
return t, scan.err
}
// Assemble the replacement string.
if t.str == "" {
t.pVariant, t.pExt = byte(uStart-1), uint16(uStart-1)
t.str = string(buf[:uStart+len(b)])
} else {
s := t.str
start, end, hasExt := t.findTypeForKey(key)
if start == end {
if hasExt {
b = b[2:]
}
t.str = fmt.Sprintf("%s-%s%s", s[:start], b, s[end:])
} else {
t.str = fmt.Sprintf("%s%s%s", s[:start], value, s[end:])
}
}
return t, nil
}
// findKeyAndType returns the start and end position for the type corresponding
// to key or the point at which to insert the key-value pair if the type
// wasn't found. The hasExt return value reports whether an -u extension was present.
// Note: the extensions are typically very small and are likely to contain
// only one key-type pair.
func (t Tag) findTypeForKey(key string) (start, end int, hasExt bool) {
p := int(t.pExt)
if len(key) != 2 || p == len(t.str) || p == 0 {
return p, p, false
}
s := t.str
// Find the correct extension.
for p++; s[p] != 'u'; p++ {
if s[p] > 'u' {
p--
return p, p, false
}
if p = nextExtension(s, p); p == len(s) {
return len(s), len(s), false
}
}
// Proceed to the hyphen following the extension name.
p++
// curKey is the key currently being processed.
curKey := ""
// Iterate over keys until we get the end of a section.
for {
// p points to the hyphen preceding the current token.
if p3 := p + 3; s[p3] == '-' {
// Found a key.
// Check whether we just processed the key that was requested.
if curKey == key {
return start, p, true
}
// Set to the next key and continue scanning type tokens.
curKey = s[p+1 : p3]
if curKey > key {
return p, p, true
}
// Start of the type token sequence.
start = p + 4
// A type is at least 3 characters long.
p += 7 // 4 + 3
} else {
// Attribute or type, which is at least 3 characters long.
p += 4
}
// p points past the third character of a type or attribute.
max := p + 5 // maximum length of token plus hyphen.
if len(s) < max {
max = len(s)
}
for ; p < max && s[p] != '-'; p++ {
}
// Bail if we have exhausted all tokens or if the next token starts
// a new extension.
if p == len(s) || s[p+2] == '-' {
if curKey == key {
return start, p, true
}
return p, p, true
}
}
}
// ParseBase parses a 2- or 3-letter ISO 639 code.
// It returns a ValueError if s is a well-formed but unknown language identifier
// or another error if another error occurred.
func ParseBase(s string) (Language, error) {
if n := len(s); n < 2 || 3 < n {
return 0, ErrSyntax
}
var buf [3]byte
return getLangID(buf[:copy(buf[:], s)])
}
// ParseScript parses a 4-letter ISO 15924 code.
// It returns a ValueError if s is a well-formed but unknown script identifier
// or another error if another error occurred.
func ParseScript(s string) (Script, error) {
if len(s) != 4 {
return 0, ErrSyntax
}
var buf [4]byte
return getScriptID(script, buf[:copy(buf[:], s)])
}
// EncodeM49 returns the Region for the given UN M.49 code.
// It returns an error if r is not a valid code.
func EncodeM49(r int) (Region, error) {
return getRegionM49(r)
}
// ParseRegion parses a 2- or 3-letter ISO 3166-1 or a UN M.49 code.
// It returns a ValueError if s is a well-formed but unknown region identifier
// or another error if another error occurred.
func ParseRegion(s string) (Region, error) {
if n := len(s); n < 2 || 3 < n {
return 0, ErrSyntax
}
var buf [3]byte
return getRegionID(buf[:copy(buf[:], s)])
}
// IsCountry returns whether this region is a country or autonomous area. This
// includes non-standard definitions from CLDR.
func (r Region) IsCountry() bool {
if r == 0 || r.IsGroup() || r.IsPrivateUse() && r != _XK {
return false
}
return true
}
// IsGroup returns whether this region defines a collection of regions. This
// includes non-standard definitions from CLDR.
func (r Region) IsGroup() bool {
if r == 0 {
return false
}
return int(regionInclusion[r]) < len(regionContainment)
}
// Contains returns whether Region c is contained by Region r. It returns true
// if c == r.
func (r Region) Contains(c Region) bool {
if r == c {
return true
}
g := regionInclusion[r]
if g >= nRegionGroups {
return false
}
m := regionContainment[g]
d := regionInclusion[c]
b := regionInclusionBits[d]
// A contained country may belong to multiple disjoint groups. Matching any
// of these indicates containment. If the contained region is a group, it
// must strictly be a subset.
if d >= nRegionGroups {
return b&m != 0
}
return b&^m == 0
}
var errNoTLD = errors.New("language: region is not a valid ccTLD")
// TLD returns the country code top-level domain (ccTLD). UK is returned for GB.
// In all other cases it returns either the region itself or an error.
//
// This method may return an error for a region for which there exists a
// canonical form with a ccTLD. To get that ccTLD canonicalize r first. The
// region will already be canonicalized it was obtained from a Tag that was
// obtained using any of the default methods.
func (r Region) TLD() (Region, error) {
// See http://en.wikipedia.org/wiki/Country_code_top-level_domain for the
// difference between ISO 3166-1 and IANA ccTLD.
if r == _GB {
r = _UK
}
if (r.typ() & ccTLD) == 0 {
return 0, errNoTLD
}
return r, nil
}
// Canonicalize returns the region or a possible replacement if the region is
// deprecated. It will not return a replacement for deprecated regions that
// are split into multiple regions.
func (r Region) Canonicalize() Region {
if cr := normRegion(r); cr != 0 {
return cr
}
return r
}
// Variant represents a registered variant of a language as defined by BCP 47.
type Variant struct {
ID uint8
str string
}
// ParseVariant parses and returns a Variant. An error is returned if s is not
// a valid variant.
func ParseVariant(s string) (Variant, error) {
s = strings.ToLower(s)
if id, ok := variantIndex[s]; ok {
return Variant{id, s}, nil
}
return Variant{}, NewValueError([]byte(s))
}
// String returns the string representation of the variant.
func (v Variant) String() string {
return v.str
}

Some files were not shown because too many files have changed in this diff Show More