tq: make strings translatable

Remove the Verb method on the Direction object in favor of a method
formatting the operation in progress.  This is easier to translate and
will prevent sentence fragments from appearing in strings.

Additionally, move a variable down into a function so that we can
translate it, since strings at the top level cannot be translated due to
the locale object not being initialized yet.
This commit is contained in:
brian m. carlson 2021-12-14 17:28:16 +00:00
parent abadadaf82
commit 08774bf091
No known key found for this signature in database
GPG Key ID: 2D0C9BC12F82B3A1
12 changed files with 91 additions and 91 deletions

@ -7,8 +7,10 @@ import (
"strings"
"sync"
"github.com/git-lfs/git-lfs/v3/errors"
"github.com/git-lfs/git-lfs/v3/fs"
"github.com/git-lfs/git-lfs/v3/lfsapi"
"github.com/git-lfs/git-lfs/v3/tr"
"github.com/rubyist/tracerx"
)
@ -208,7 +210,7 @@ func (a *adapterBase) newHTTPRequest(method string, rel *Action) (*http.Request,
if !httpRE.MatchString(href) {
urlfragment := strings.SplitN(href, "?", 2)[0]
return nil, fmt.Errorf("missing protocol: %q", urlfragment)
return nil, errors.New(tr.Tr.Get("missing protocol: %q", urlfragment))
}
req, err := http.NewRequest(method, href, nil)

@ -1,13 +1,13 @@
package tq
import (
"fmt"
"time"
"github.com/git-lfs/git-lfs/v3/errors"
"github.com/git-lfs/git-lfs/v3/git"
"github.com/git-lfs/git-lfs/v3/lfsapi"
"github.com/git-lfs/git-lfs/v3/lfshttp"
"github.com/git-lfs/git-lfs/v3/tr"
"github.com/rubyist/tracerx"
)
@ -83,7 +83,7 @@ func (c *tqClient) Batch(remote string, bReq *batchRequest) (*BatchResponse, err
req, err := c.NewRequest("POST", bRes.endpoint, "objects/batch", bReq)
if err != nil {
return nil, errors.Wrap(err, "batch request")
return nil, errors.Wrap(err, tr.Tr.Get("batch request"))
}
tracerx.Printf("api: batch %d files", len(bReq.Objects))
@ -92,15 +92,15 @@ func (c *tqClient) Batch(remote string, bReq *batchRequest) (*BatchResponse, err
res, err := c.DoAPIRequestWithAuth(remote, lfshttp.WithRetries(req, c.MaxRetries()))
if err != nil {
tracerx.Printf("api error: %s", err)
return nil, errors.Wrap(err, "batch response")
return nil, errors.Wrap(err, tr.Tr.Get("batch response"))
}
if err := lfshttp.DecodeJSON(res, bRes); err != nil {
return bRes, errors.Wrap(err, "batch response")
return bRes, errors.Wrap(err, tr.Tr.Get("batch response"))
}
if bRes.HashAlgorithm != "" && bRes.HashAlgorithm != "sha256" {
return bRes, errors.Wrap(fmt.Errorf("unsupported hash algorithm"), "batch response")
return bRes, errors.Wrap(errors.New(tr.Tr.Get("unsupported hash algorithm")), tr.Tr.Get("batch response"))
}
if res.StatusCode != 200 {

@ -12,6 +12,7 @@ import (
"github.com/git-lfs/git-lfs/v3/lfsapi"
"github.com/git-lfs/git-lfs/v3/lfshttp"
"github.com/git-lfs/git-lfs/v3/tr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/xeipuuv/gojsonschema"
@ -167,7 +168,7 @@ func getSchema(wd, relpath string) *sourcedSchema {
abspath := filepath.ToSlash(filepath.Join(wd, relpath))
s, err := gojsonschema.NewSchema(gojsonschema.NewReferenceLoader(fmt.Sprintf("file:///%s", abspath)))
if err != nil {
fmt.Printf("schema load error for %q: %+v\n", relpath, err)
tr.Tr.Get("schema load error for %q: %+v\n", relpath, err)
}
return &sourcedSchema{Source: relpath, Schema: s}
}
@ -184,6 +185,6 @@ func assertSchema(t *testing.T, schema *sourcedSchema, dataLoader gojsonschema.J
for _, resErr := range resErrors {
valErrors = append(valErrors, resErr.String())
}
t.Errorf("Schema: %s\n%s", schema.Source, strings.Join(valErrors, "\n"))
t.Errorf(tr.Tr.Get("Schema: %s\n%s", schema.Source, strings.Join(valErrors, "\n")))
}
}

@ -12,6 +12,7 @@ import (
"github.com/git-lfs/git-lfs/v3/errors"
"github.com/git-lfs/git-lfs/v3/tools"
"github.com/git-lfs/git-lfs/v3/tr"
"github.com/rubyist/tracerx"
)
@ -116,7 +117,7 @@ func (a *basicDownloadAdapter) download(t *Transfer, cb ProgressCallback, authOk
return err
}
if rel == nil {
return errors.Errorf("Object %s not found on the server.", t.Oid)
return errors.Errorf(tr.Tr.Get("Object %s not found on the server.", t.Oid))
}
req, err := a.newHTTPRequest("GET", rel)
@ -241,15 +242,15 @@ func (a *basicDownloadAdapter) download(t *Transfer, cb ProgressCallback, authOk
}
written, err := tools.CopyWithCallback(dlFile, hasher, res.ContentLength, ccb)
if err != nil {
return errors.Wrapf(err, "cannot write data to tempfile %q", dlfilename)
return errors.Wrapf(err, tr.Tr.Get("cannot write data to temporary file %q", dlfilename))
}
if actual := hasher.Hash(); actual != t.Oid {
return fmt.Errorf("expected OID %s, got %s after %d bytes written", t.Oid, actual, written)
return errors.New(tr.Tr.Get("expected OID %s, got %s after %d bytes written", t.Oid, actual, written))
}
if err := dlFile.Close(); err != nil {
return fmt.Errorf("can't close tempfile %q: %v", dlfilename, err)
return errors.New(tr.Tr.Get("can't close temporary file %q: %v", dlfilename, err))
}
err = tools.RenameFileCopyPermissions(dlfilename, t.Path)

@ -13,6 +13,7 @@ import (
"github.com/git-lfs/git-lfs/v3/errors"
"github.com/git-lfs/git-lfs/v3/lfsapi"
"github.com/git-lfs/git-lfs/v3/tools"
"github.com/git-lfs/git-lfs/v3/tr"
)
const (
@ -46,7 +47,7 @@ func (a *basicUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb Progres
return err
}
if rel == nil {
return errors.Errorf("No upload action for object: %s", t.Oid)
return errors.Errorf(tr.Tr.Get("No upload action for object: %s", t.Oid))
}
req, err := a.newHTTPRequest("PUT", rel)
@ -136,16 +137,16 @@ func (a *basicUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb Progres
// A status code of 403 likely means that an authentication token for the
// upload has expired. This can be safely retried.
if res.StatusCode == 403 {
err = errors.New("http: received status 403")
err = errors.New(tr.Tr.Get("http: received status 403"))
return errors.NewRetriableError(err)
}
if res.StatusCode > 299 {
return errors.Wrapf(nil, "Invalid status for %s %s: %d",
return errors.Wrapf(nil, tr.Tr.Get("Invalid status for %s %s: %d",
req.Method,
strings.SplitN(req.URL.String(), "?", 2)[0],
res.StatusCode,
)
))
}
io.Copy(ioutil.Discard, res.Body)
@ -167,12 +168,12 @@ func (a *adapterBase) setContentTypeFor(req *http.Request, r io.ReadSeeker) erro
buffer := make([]byte, 512)
n, err := r.Read(buffer)
if err != nil && err != io.EOF {
return errors.Wrap(err, "content type detect")
return errors.Wrap(err, tr.Tr.Get("content type detection error"))
}
contentType = http.DetectContentType(buffer[:n])
if _, err := r.Seek(0, io.SeekStart); err != nil {
return errors.Wrap(err, "content type rewind")
return errors.Wrap(err, tr.Tr.Get("content type rewind failure"))
}
}

@ -14,6 +14,7 @@ import (
"github.com/git-lfs/git-lfs/v3/errors"
"github.com/git-lfs/git-lfs/v3/fs"
"github.com/git-lfs/git-lfs/v3/tools"
"github.com/git-lfs/git-lfs/v3/tr"
"github.com/git-lfs/git-lfs/v3/subprocess"
"github.com/rubyist/tracerx"
@ -127,11 +128,11 @@ func (a *customAdapter) WorkerStarting(workerNum int) (interface{}, error) {
cmd := subprocess.ExecCommand(cmdName, cmdArgs...)
outp, err := cmd.StdoutPipe()
if err != nil {
return nil, fmt.Errorf("failed to get stdout for custom transfer command %q remote: %v", a.path, err)
return nil, errors.New(tr.Tr.Get("failed to get stdout for custom transfer command %q remote: %v", a.path, err))
}
inp, err := cmd.StdinPipe()
if err != nil {
return nil, fmt.Errorf("failed to get stdin for custom transfer command %q remote: %v", a.path, err)
return nil, errors.New(tr.Tr.Get("failed to get stdin for custom transfer command %q remote: %v", a.path, err))
}
// Capture stderr to trace
tracer := &traceWriter{}
@ -139,7 +140,7 @@ func (a *customAdapter) WorkerStarting(workerNum int) (interface{}, error) {
cmd.Stderr = tracer
err = cmd.Start()
if err != nil {
return nil, fmt.Errorf("failed to start custom transfer command %q remote: %v", a.path, err)
return nil, errors.New(tr.Tr.Get("failed to start custom transfer command %q remote: %v", a.path, err))
}
// Set up buffered reader/writer since we operate on lines
ctx := &customAdapterWorkerContext{workerNum, cmd, outp, bufio.NewReader(outp), inp, tracer}
@ -155,7 +156,7 @@ func (a *customAdapter) WorkerStarting(workerNum int) (interface{}, error) {
}
if resp.Error != nil {
a.abortWorkerProcess(ctx)
return nil, fmt.Errorf("error initializing custom adapter %q worker %d: %v", a.name, workerNum, resp.Error)
return nil, errors.New(tr.Tr.Get("error initializing custom adapter %q worker %d: %v", a.name, workerNum, resp.Error))
}
a.Trace("xfer: started custom adapter process %q for worker %d OK", a.path, workerNum)
@ -227,7 +228,7 @@ func (a *customAdapter) shutdownWorkerProcess(ctx *customAdapterWorkerContext) e
case err := <-finishChan:
return err
case <-time.After(30 * time.Second):
return fmt.Errorf("timeout while shutting down worker process %d", ctx.workerNum)
return errors.New(tr.Tr.Get("timeout while shutting down worker process %d", ctx.workerNum))
}
}
@ -254,12 +255,12 @@ func (a *customAdapter) WorkerEnding(workerNum int, ctx interface{}) {
func (a *customAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressCallback, authOkFunc func()) error {
if ctx == nil {
return fmt.Errorf("custom transfer %q was not properly initialized, see previous errors", a.name)
return errors.New(tr.Tr.Get("custom transfer %q was not properly initialized, see previous errors", a.name))
}
customCtx, ok := ctx.(*customAdapterWorkerContext)
if !ok {
return fmt.Errorf("context object for custom transfer %q was of the wrong type", a.name)
return errors.New(tr.Tr.Get("context object for custom transfer %q was of the wrong type", a.name))
}
var authCalled bool
@ -268,7 +269,7 @@ func (a *customAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressCall
return err
}
if rel == nil && !a.standalone {
return errors.Errorf("Object %s not found on the server.", t.Oid)
return errors.Errorf(tr.Tr.Get("Object %s not found on the server.", t.Oid))
}
var req *customAdapterTransferRequest
if a.direction == Upload {
@ -292,7 +293,7 @@ func (a *customAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressCall
case "progress":
// Progress
if resp.Oid != t.Oid {
return fmt.Errorf("unexpected oid %q in response, expecting %q", resp.Oid, t.Oid)
return errors.New(tr.Tr.Get("unexpected OID %q in response, expecting %q", resp.Oid, t.Oid))
}
if cb != nil {
cb(t.Name, t.Size, resp.BytesSoFar, resp.BytesSinceLast)
@ -301,19 +302,19 @@ func (a *customAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressCall
case "complete":
// Download/Upload complete
if resp.Oid != t.Oid {
return fmt.Errorf("unexpected oid %q in response, expecting %q", resp.Oid, t.Oid)
return errors.New(tr.Tr.Get("unexpected OID %q in response, expecting %q", resp.Oid, t.Oid))
}
if resp.Error != nil {
return fmt.Errorf("error transferring %q: %v", t.Oid, resp.Error)
return errors.New(tr.Tr.Get("error transferring %q: %v", t.Oid, resp.Error))
}
if a.direction == Download {
// So we don't have to blindly trust external providers, check SHA
if err = tools.VerifyFileHash(t.Oid, resp.Path); err != nil {
return fmt.Errorf("downloaded file failed checks: %v", err)
return errors.New(tr.Tr.Get("downloaded file failed checks: %v", err))
}
// Move file to final location
if err = tools.RenameFileCopyPermissions(resp.Path, t.Path); err != nil {
return fmt.Errorf("failed to copy downloaded file: %v", err)
return errors.New(tr.Tr.Get("failed to copy downloaded file: %v", err))
}
} else if a.direction == Upload {
if err = verifyUpload(a.apiClient, a.remote, t); err != nil {
@ -323,7 +324,7 @@ func (a *customAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressCall
wasAuthOk = true
complete = true
default:
return fmt.Errorf("invalid message %q from custom adapter %q", resp.Event, a.name)
return errors.New(tr.Tr.Get("invalid message %q from custom adapter %q", resp.Event, a.name))
}
// Fall through from both progress and completion messages
// Call auth on first progress or success to free up other workers

@ -1,6 +1,6 @@
package tq
import "fmt"
import "github.com/git-lfs/git-lfs/v3/tr"
type MalformedObjectError struct {
Name string
@ -23,7 +23,7 @@ func (e MalformedObjectError) Corrupt() bool { return !e.Missing() }
func (e MalformedObjectError) Error() string {
if e.Corrupt() {
return fmt.Sprintf("corrupt object: %s (%s)", e.Name, e.Oid)
return tr.Tr.Get("corrupt object: %s (%s)", e.Name, e.Oid)
}
return fmt.Sprintf("missing object: %s (%s)", e.Name, e.Oid)
return tr.Tr.Get("missing object: %s (%s)", e.Name, e.Oid)
}

@ -13,6 +13,7 @@ import (
"github.com/git-lfs/git-lfs/v3/tasklog"
"github.com/git-lfs/git-lfs/v3/tools"
"github.com/git-lfs/git-lfs/v3/tools/humanize"
"github.com/git-lfs/git-lfs/v3/tr"
)
// Meter provides a progress bar type output for the TransferQueue. It
@ -54,11 +55,11 @@ func (m *Meter) LoggerFromEnv(os env) *tools.SyncWriter {
func (m *Meter) LoggerToFile(name string) *tools.SyncWriter {
printErr := func(err string) {
fmt.Fprintf(os.Stderr, "Error creating progress logger: %s\n", err)
fmt.Fprintf(os.Stderr, tr.Tr.Get("Error creating progress logger: %s\n", err))
}
if !filepath.IsAbs(name) {
printErr("GIT_LFS_PROGRESS must be an absolute path")
printErr(tr.Tr.Get("GIT_LFS_PROGRESS must be an absolute path"))
return nil
}
@ -235,8 +236,8 @@ func (m *Meter) str() string {
// (Uploading|Downloading) LFS objects: 100% (10/10) 100 MiB | 10 MiB/s
percentage := 100 * float64(m.finishedFiles) / float64(m.estimatedFiles)
return fmt.Sprintf("%s LFS objects: %3.f%% (%d/%d), %s | %s",
m.Direction.Verb(),
return fmt.Sprintf("%s: %3.f%% (%d/%d), %s | %s",
m.Direction.Progress(),
percentage,
m.finishedFiles, m.estimatedFiles,
humanize.FormatBytes(clamp(m.currentBytes)),

@ -16,6 +16,7 @@ import (
"github.com/git-lfs/git-lfs/v3/lfshttp"
"github.com/git-lfs/git-lfs/v3/ssh"
"github.com/git-lfs/git-lfs/v3/tools"
"github.com/git-lfs/git-lfs/v3/tr"
"github.com/rubyist/tracerx"
)
@ -30,12 +31,12 @@ func (a *SSHBatchClient) batchInternal(args []string, batchLines []string) (int,
defer conn.Unlock()
err := conn.SendMessageWithLines("batch", args, batchLines)
if err != nil {
return 0, nil, nil, errors.Wrap(err, "batch request")
return 0, nil, nil, errors.Wrap(err, tr.Tr.Get("batch request"))
}
status, args, lines, err := conn.ReadStatusWithLines()
if err != nil {
return status, nil, nil, errors.Wrap(err, "batch response")
return status, nil, nil, errors.Wrap(err, tr.Tr.Get("batch response"))
}
return status, args, lines, err
}
@ -66,11 +67,11 @@ func (a *SSHBatchClient) Batch(remote string, bReq *batchRequest) (*BatchRespons
}
if status != 200 {
msg := "no message provided"
msg := tr.Tr.Get("no message provided")
if len(lines) > 0 {
msg = lines[0]
}
return nil, fmt.Errorf("batch response: status %d from server (%s)", status, msg)
return nil, errors.New(tr.Tr.Get("batch response: status %d from server (%s)", status, msg))
}
for _, arg := range args {
@ -81,7 +82,7 @@ func (a *SSHBatchClient) Batch(remote string, bReq *batchRequest) (*BatchRespons
if entries[0] == "hash-algo" {
bRes.HashAlgorithm = entries[1]
if bRes.HashAlgorithm != "sha256" {
return nil, fmt.Errorf("batch response: unsupported hash algorithm: %q", entries[1])
return nil, errors.New(tr.Tr.Get("batch response: unsupported hash algorithm: %q", entries[1]))
}
}
}
@ -90,7 +91,7 @@ func (a *SSHBatchClient) Batch(remote string, bReq *batchRequest) (*BatchRespons
for _, line := range lines {
entries := strings.Split(line, " ")
if len(entries) < 3 {
return nil, fmt.Errorf("batch response: malformed response: %q", line)
return nil, errors.New(tr.Tr.Get("batch response: malformed response: %q", line))
}
length := len(bRes.Objects)
if length == 0 || bRes.Objects[length-1].Oid != entries[0] {
@ -100,7 +101,7 @@ func (a *SSHBatchClient) Batch(remote string, bReq *batchRequest) (*BatchRespons
transfer.Oid = entries[0]
transfer.Size, err = strconv.ParseInt(entries[1], 10, 64)
if err != nil {
return nil, fmt.Errorf("batch response: invalid size: %s", entries[1])
return nil, errors.New(tr.Tr.Get("batch response: invalid size: %s", entries[1]))
}
if entries[2] == "noop" {
continue
@ -115,12 +116,12 @@ func (a *SSHBatchClient) Batch(remote string, bReq *batchRequest) (*BatchRespons
} else if strings.HasPrefix(entry, "expires-in=") {
transfer.Actions[entries[2]].ExpiresIn, err = strconv.Atoi(entry[11:])
if err != nil {
return nil, fmt.Errorf("batch response: invalid expires-in: %s", entry)
return nil, errors.New(tr.Tr.Get("batch response: invalid expires-in: %s", entry))
}
} else if strings.HasPrefix(entry, "expires-at=") {
transfer.Actions[entries[2]].ExpiresAt, err = time.Parse(time.RFC3339, entry[11:])
if err != nil {
return nil, fmt.Errorf("batch response: invalid expires-at: %s", entry)
return nil, errors.New(tr.Tr.Get("batch response: invalid expires-at: %s", entry))
}
}
}
@ -191,7 +192,7 @@ func (a *SSHAdapter) download(t *Transfer, conn *ssh.PktlineConnection, cb Progr
return err
}
if rel == nil {
return errors.Errorf("No download action for object: %s", t.Oid)
return errors.Errorf(tr.Tr.Get("No download action for object: %s", t.Oid))
}
// Reserve a temporary filename. We need to make sure nobody operates on the file simultaneously with us.
f, err := tools.TempFile(a.tempDir(), t.Oid, a.fs)
@ -228,7 +229,7 @@ func (a *SSHAdapter) doDownload(t *Transfer, conn *ssh.PktlineConnection, f *os.
io.CopyN(buffer, data, 1024)
io.Copy(ioutil.Discard, data)
}
return errors.NewRetriableError(fmt.Errorf("got status %d when fetching OID %s: %s", status, t.Oid, buffer.String()))
return errors.NewRetriableError(errors.New(tr.Tr.Get("got status %d when fetching OID %s: %s", status, t.Oid, buffer.String())))
}
var actualSize int64
@ -236,11 +237,11 @@ func (a *SSHAdapter) doDownload(t *Transfer, conn *ssh.PktlineConnection, f *os.
for _, arg := range args {
if strings.HasPrefix(arg, "size=") {
if seenSize {
return errors.NewProtocolError("unexpected size argument", nil)
return errors.NewProtocolError(tr.Tr.Get("unexpected size argument"), nil)
}
actualSize, err = strconv.ParseInt(arg[5:], 10, 64)
if err != nil || actualSize < 0 {
return errors.NewProtocolError(fmt.Sprintf("expected valid size, got %q", arg[5:]), err)
return errors.NewProtocolError(tr.Tr.Get("expected valid size, got %q", arg[5:]), err)
}
seenSize = true
}
@ -260,15 +261,15 @@ func (a *SSHAdapter) doDownload(t *Transfer, conn *ssh.PktlineConnection, f *os.
hasher := tools.NewHashingReader(data)
written, err := tools.CopyWithCallback(f, hasher, t.Size, ccb)
if err != nil {
return errors.Wrapf(err, "cannot write data to tempfile %q", dlfilename)
return errors.Wrapf(err, tr.Tr.Get("cannot write data to temporary file %q", dlfilename))
}
if actual := hasher.Hash(); actual != t.Oid {
return fmt.Errorf("expected OID %s, got %s after %d bytes written", t.Oid, actual, written)
return errors.New(tr.Tr.Get("expected OID %s, got %s after %d bytes written", t.Oid, actual, written))
}
if err := f.Close(); err != nil {
return fmt.Errorf("can't close tempfile %q: %v", dlfilename, err)
return errors.New(tr.Tr.Get("can't close temporary file %q: %v", dlfilename, err))
}
err = tools.RenameFileCopyPermissions(dlfilename, t.Path)
@ -293,9 +294,9 @@ func (a *SSHAdapter) verifyUpload(t *Transfer, conn *ssh.PktlineConnection) erro
}
if status < 200 || status > 299 {
if len(lines) > 0 {
return fmt.Errorf("got status %d when verifying upload OID %s: %s", status, t.Oid, lines[0])
return errors.New(tr.Tr.Get("got status %d when verifying upload OID %s: %s", status, t.Oid, lines[0]))
}
return fmt.Errorf("got status %d when verifying upload OID %s", status, t.Oid)
return errors.New(tr.Tr.Get("got status %d when verifying upload OID %s", status, t.Oid))
}
return nil
}
@ -331,12 +332,12 @@ func (a *SSHAdapter) upload(t *Transfer, conn *ssh.PktlineConnection, cb Progres
return err
}
if rel == nil {
return errors.Errorf("No upload action for object: %s", t.Oid)
return errors.Errorf(tr.Tr.Get("No upload action for object: %s", t.Oid))
}
f, err := os.OpenFile(t.Path, os.O_RDONLY, 0644)
if err != nil {
return errors.Wrap(err, "SSH upload")
return errors.Wrap(err, tr.Tr.Get("SSH upload"))
}
defer f.Close()
@ -348,18 +349,18 @@ func (a *SSHAdapter) upload(t *Transfer, conn *ssh.PktlineConnection, cb Progres
// A status code of 403 likely means that an authentication token for the
// upload has expired. This can be safely retried.
if status == 403 {
err = errors.New("http: received status 403")
err = errors.New(tr.Tr.Get("http: received status 403"))
return errors.NewRetriableError(err)
}
if status == 429 {
return errors.NewRetriableError(fmt.Errorf("got status %d when uploading OID %s", status, t.Oid))
return errors.NewRetriableError(errors.New(tr.Tr.Get("got status %d when uploading OID %s", status, t.Oid)))
}
if len(lines) > 0 {
return fmt.Errorf("got status %d when uploading OID %s: %s", status, t.Oid, lines[0])
return errors.New(tr.Tr.Get("got status %d when uploading OID %s: %s", status, t.Oid, lines[0]))
}
return fmt.Errorf("got status %d when uploading OID %s", status, t.Oid)
return errors.New(tr.Tr.Get("got status %d when uploading OID %s", status, t.Oid))
}

@ -9,6 +9,7 @@ import (
"github.com/git-lfs/git-lfs/v3/errors"
"github.com/git-lfs/git-lfs/v3/lfsapi"
"github.com/git-lfs/git-lfs/v3/tools"
"github.com/git-lfs/git-lfs/v3/tr"
)
type Direction int
@ -19,15 +20,15 @@ const (
Checkout = Direction(iota)
)
// Verb returns a string containing the verb form of the receiving action.
func (d Direction) Verb() string {
// Progress returns a string containing the operation in progress.
func (d Direction) Progress() string {
switch d {
case Checkout:
return "Checking out"
return tr.Tr.Get("Checking out LFS objects")
case Download:
return "Downloading"
return tr.Tr.Get("Downloading LFS objects")
case Upload:
return "Uploading"
return tr.Tr.Get("Uploading LFS objects")
default:
return "<unknown>"
}

@ -11,6 +11,7 @@ import (
"github.com/git-lfs/git-lfs/v3/git"
"github.com/git-lfs/git-lfs/v3/lfshttp"
"github.com/git-lfs/git-lfs/v3/tools"
"github.com/git-lfs/git-lfs/v3/tr"
"github.com/rubyist/tracerx"
)
@ -626,7 +627,7 @@ func (q *TransferQueue) enqueueAndCollectRetriesFor(batch batch) (batch, error)
// Transfer object, then we give up on the
// transfer by telling the progress meter to
// skip the number of bytes in "o".
q.errorc <- errors.Errorf("[%v] The server returned an unknown OID.", o.Oid)
q.errorc <- errors.Errorf(tr.Tr.Get("[%v] The server returned an unknown OID.", o.Oid))
q.Skip(o.Size)
q.wait.Done()
@ -722,7 +723,7 @@ func (q *TransferQueue) partitionTransfers(transfers []*Transfer) (present []*Tr
var err error
if t.Size < 0 {
err = errors.Errorf("Git LFS: object %q has invalid size (got: %d)", t.Oid, t.Size)
err = errors.Errorf(tr.Tr.Get("Git LFS: object %q has invalid size (got: %d)", t.Oid, t.Size))
} else {
fd, serr := os.Stat(t.Path)
if serr != nil {
@ -921,17 +922,6 @@ func (q *TransferQueue) toAdapterCfg(e lfshttp.Endpoint) AdapterConfig {
}
}
var (
// contentTypeWarning is the message printed when a server returns an
// HTTP 422 at the end of a push.
contentTypeWarning = []string{
"Uploading failed due to unsupported Content-Type header(s).",
"Consider disabling Content-Type detection with:",
"",
" $ git config lfs.contenttype false",
}
)
// Wait waits for the queue to finish processing all transfers. Once Wait is
// called, Add will no longer add transfers to the queue. Any failed
// transfers will be automatically retried once.
@ -956,9 +946,10 @@ func (q *TransferQueue) Wait() {
}
if q.unsupportedContentType {
for _, line := range contentTypeWarning {
fmt.Fprintf(os.Stderr, "info: %s\n", line)
}
fmt.Fprintf(os.Stderr, tr.Tr.Get(`info: Uploading failed due to unsupported Content-Type header(s).
info: Consider disabling Content-Type detection with:
info:
info: $ git config lfs.contenttype false`))
}
}

@ -1,7 +1,6 @@
package tq
import (
"fmt"
"io"
"io/ioutil"
"os"
@ -11,6 +10,7 @@ import (
"github.com/git-lfs/git-lfs/v3/errors"
"github.com/git-lfs/git-lfs/v3/lfsapi"
"github.com/git-lfs/git-lfs/v3/tools"
"github.com/git-lfs/git-lfs/v3/tr"
)
const (
@ -35,7 +35,7 @@ func (a *tusUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressC
return err
}
if rel == nil {
return errors.Errorf("No upload action for object: %s", t.Oid)
return errors.Errorf(tr.Tr.Get("No upload action for object: %s", t.Oid))
}
// Note not supporting the Creation extension since the batch API generates URLs
@ -59,11 +59,11 @@ func (a *tusUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressC
// Response will contain Upload-Offset if supported
offHdr := res.Header.Get("Upload-Offset")
if len(offHdr) == 0 {
return fmt.Errorf("missing Upload-Offset header from tus.io HEAD response at %q, contact server admin", rel.Href)
return errors.New(tr.Tr.Get("missing Upload-Offset header from tus.io HEAD response at %q, contact server admin", rel.Href))
}
offset, err := strconv.ParseInt(offHdr, 10, 64)
if err != nil || offset < 0 {
return fmt.Errorf("invalid Upload-Offset value %q in response from tus.io HEAD at %q, contact server admin", offHdr, rel.Href)
return errors.New(tr.Tr.Get("invalid Upload-Offset value %q in response from tus.io HEAD at %q, contact server admin", offHdr, rel.Href))
}
// Upload-Offset=size means already completed (skip)
// Batch API will probably already detect this, but handle just in case
@ -138,16 +138,16 @@ func (a *tusUploadAdapter) DoTransfer(ctx interface{}, t *Transfer, cb ProgressC
// A status code of 403 likely means that an authentication token for the
// upload has expired. This can be safely retried.
if res.StatusCode == 403 {
err = errors.New("http: received status 403")
err = errors.New(tr.Tr.Get("http: received status 403"))
return errors.NewRetriableError(err)
}
if res.StatusCode > 299 {
return errors.Wrapf(nil, "Invalid status for %s %s: %d",
return errors.Wrapf(nil, tr.Tr.Get("Invalid status for %s %s: %d",
req.Method,
strings.SplitN(req.URL.String(), "?", 2)[0],
res.StatusCode,
)
))
}
io.Copy(ioutil.Discard, res.Body)