Repository: etcd-io/etcd
File: tests/framework/e2e/etcdctl.go (Go)

Code before:
		// nothing
	default:
		return nil, fmt.Errorf("bad sort target %v", o.SortBy)
	}
	switch o.Order {
	case clientv3.SortAscend:
		args = append(args, "--order=ASCEND")
	case clientv3.SortDescend:
		args = append(args, "--order=DESCEND")
	case clientv3.SortNone:
		// nothing
	default:
		return nil, fmt.Errorf("bad sort order %v", o.Order)
	}
	if o.CountOnly {
		cmd, err := SpawnCmd(ctl.cmdArgs(args...), nil)
		if err != nil {
			return nil, err
		}
		defer cmd.Close()
		respCount, err := cmd.ExpectWithContext(ctx, expect.ExpectedResponse{Value: "Count"})
		if err != nil {
			return nil, err
		}
		count, err := strconv.Atoi(strings.TrimSpace(strings.Split(respCount, ":")[1]))
		resp.Count = int64(count)
		return &resp, err
	}
	err := ctl.spawnJSONCmd(ctx, &resp, args...)
	return &resp, err
}

func (ctl *EtcdctlV3) Put(ctx context.Context, key, value string, opts config.PutOptions) (*clientv3.PutResponse, error) {
	resp := clientv3.PutResponse{}
	args := []string{}
	args = append(args, "put", key, value)
	if opts.LeaseID != 0 {
		args = append(args, "--lease", strconv.FormatInt(int64(opts.LeaseID), 16))
	}
	if opts.Timeout != 0 {
		args = append(args, fmt.Sprintf("--command-timeout=%s", opts.Timeout))
	}
	err := ctl.spawnJSONCmd(ctx, &resp, args...)
	return &resp, err
}

func (ctl *EtcdctlV3) Delete(ctx context.Context, key string, o config.DeleteOptions) (*clientv3.DeleteResponse, error) {
	args := []string{"del", key}
	if o.End != "" {
		args = append(args, o.End)
	}

Review comment (suggestion):
There are also other fields, can we parse all of them since this method `(*EtcdctlV3) Get` is a common method? If we intentionally ignore other fields, at least we should add a comment.

```
$ etcdctl  get k1 --count-only -w fields
"ClusterID" : 14841639068965178418
"MemberID" : 10276657743932975437
"Revision" : 319
"RaftTerm" : 11
"More" : false
"Count" : 1
```

Code after:
	default:
		return nil, fmt.Errorf("bad sort target %v", o.SortBy)
	}
	switch o.Order {
	case clientv3.SortAscend:
		args = append(args, "--order=ASCEND")
	case clientv3.SortDescend:
		args = append(args, "--order=DESCEND")
	case clientv3.SortNone:
		// nothing
	default:
		return nil, fmt.Errorf("bad sort order %v", o.Order)
	}
	if o.CountOnly {
		cmd, err := SpawnCmd(ctl.cmdArgs(args...), nil)
		if err != nil {
			return nil, err
		}
		defer cmd.Close()
		// Relying on finding 'Count' as the last line of the output to get all the lines from cmd.Lines()
		_, err = cmd.ExpectWithContext(ctx, expect.ExpectedResponse{Value: "Count"})
		if err != nil {
			return nil, err
		}
		return parseFieldsGetResponse(cmd.Lines())
	}
	resp := clientv3.GetResponse{}
	err := ctl.spawnJSONCmd(ctx, &resp, args...)
	return &resp, err
}

func parseFieldsGetResponse(lines []string) (*clientv3.GetResponse, error) {
	resp := &clientv3.GetResponse{Header: &etcdserverpb.ResponseHeader{}}
	for _, l := range lines {
		fields := strings.Split(l, ":")
		key, value := strings.TrimSpace(fields[0]), strings.TrimSpace(fields[1])
		var err error
		if key, err = strconv.Unquote(key); err != nil {
			return resp, err
		}
		switch key {
		case "ClusterID":
			resp.Header.ClusterId, err = strconv.ParseUint(value, 10, 64)
		case "MemberID":
			resp.Header.MemberId, err = strconv.ParseUint(value, 10, 64)
		case "Revision":
			resp.Header.Revision, err = strconv.ParseInt(value, 10, 64)
		case "RaftTerm":
			resp.Header.RaftTerm, err = strconv.ParseUint(value, 10, 64)
		case "More":
			resp.More, err = strconv.ParseBool(value)