<commit_before>package commands

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	gopath "path"
	"strings"

	cmds "github.com/ipfs/go-ipfs/commands"
	core "github.com/ipfs/go-ipfs/core"
	dag "github.com/ipfs/go-ipfs/merkledag"
	mfs "github.com/ipfs/go-ipfs/mfs"
	path "github.com/ipfs/go-ipfs/path"
	ft "github.com/ipfs/go-ipfs/unixfs"

	context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
	logging "gx/ipfs/QmaDNZ4QMdBdku1YZWBysufYyoQt1negQGNav6PLYarbY8/go-log"
)

var log = logging.Logger("cmds/files")

var FilesCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Manipulate unixfs files.",
		ShortDescription: `
Files is an API for manipulating IPFS objects as if they were a unix filesystem.

NOTE:
Most of the subcommands of 'ipfs files' accept the '--flush' flag. It defaults to
true. Use caution when setting this flag to false. It will improve performance
for large numbers of file operations, but it does so at the cost of consistency
guarantees. If the daemon is unexpectedly killed before running 'ipfs files flush'
on the files in question, then data may be lost. This also applies to running
'ipfs repo gc' concurrently with '--flush=false' operations.
`,
	},
	Options: []cmds.Option{
		cmds.BoolOption("f", "flush", "Flush target and ancestors after write. Default: true."),
	},
	Subcommands: map[string]*cmds.Command{
		"read":  FilesReadCmd,
		"write": FilesWriteCmd,
		"mv":    FilesMvCmd,
		"cp":    FilesCpCmd,
		"ls":    FilesLsCmd,
		"mkdir": FilesMkdirCmd,
		"stat":  FilesStatCmd,
		"rm":    FilesRmCmd,
		"flush": FilesFlushCmd,
	},
}

var formatError = errors.New("Format was set by multiple options. Only one format option is allowed")

var FilesStatCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Display file status.",
	},

	Arguments: []cmds.Argument{
		cmds.StringArg("path", true, false, "Path to node to stat."),
	},
	Options: []cmds.Option{
		cmds.StringOption("format", "Print statistics in given format. Allowed tokens: "+
			"<hash> <size> <cumulsize> <type> <childs>. Conflicts with other format options.").Default(
			`<hash>
Size: <size>
CumulativeSize: <cumulsize>
ChildBlocks: <childs>
Type: <type>`),
		cmds.BoolOption("hash", "Print only hash. Implies '--format=<hash>. Conflicts with other format options.").Default(false),
		cmds.BoolOption("size", "Print only size. Implies '--format=<cumulsize>. Conflicts with other format options.").Default(false),
	},
	Run: func(req cmds.Request, res cmds.Response) {

		_, err := statGetFormatOptions(req)
		if err != nil {
			res.SetError(err, cmds.ErrClient)
		}

		node, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		path, err := checkPath(req.Arguments()[0])
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		fsn, err := mfs.Lookup(node.FilesRoot, path)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		o, err := statNode(node.DAG, fsn)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		res.SetOutput(o)
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {

			out := res.Output().(*Object)
			buf := new(bytes.Buffer)

			s, _ := statGetFormatOptions(res.Request())
			s = strings.Replace(s, "<hash>", out.Hash, -1)
			s = strings.Replace(s, "<size>", fmt.Sprintf("%d", out.Size), -1)
			s = strings.Replace(s, "<cumulsize>", fmt.Sprintf("%d", out.CumulativeSize), -1)
			s = strings.Replace(s, "<childs>", fmt.Sprintf("%d", out.Blocks), -1)
			s = strings.Replace(s, "<type>", out.Type, -1)

			fmt.Fprintln(buf, s)
			return buf, nil
		},
	},
	Type: Object{},
}

func moreThanOne(a, b, c bool) bool {
	return a && b || b && c || a && c
}

func statGetFormatOptions(req cmds.Request) (string, error) {

	hash, _, _ := req.Option("hash").Bool()
	size, _, _ := req.Option("size").Bool()
	formatSpecified := req.Option("format").Found()

	if moreThanOne(hash, size, formatSpecified) {
		return "", formatError
	}

	format := ""
	if hash {
		format = "<hash>"
	}
	if size {
		format = "<cumulsize>"
	}
	if len(format) == 0 {
		format, _, _ = req.Option("format").String()
	}

	return format, nil
}

func statNode(ds dag.DAGService, fsn mfs.FSNode) (*Object, error) {
	nd, err := fsn.GetNode()
	if err != nil {
		return nil, err
	}

	k, err := nd.Key()
	if err != nil {<commit_msg>Make format logic look much better<commit_after>package commands

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"os"
	gopath "path"
	"strings"

	cmds "github.com/ipfs/go-ipfs/commands"
	core "github.com/ipfs/go-ipfs/core"
	dag "github.com/ipfs/go-ipfs/merkledag"
	mfs "github.com/ipfs/go-ipfs/mfs"
	path "github.com/ipfs/go-ipfs/path"
	ft "github.com/ipfs/go-ipfs/unixfs"

	context "gx/ipfs/QmZy2y8t9zQH2a1b8q2ZSLKp17ATuJoCNxxyMFG5qFExpt/go-net/context"
	logging "gx/ipfs/QmaDNZ4QMdBdku1YZWBysufYyoQt1negQGNav6PLYarbY8/go-log"
)

var log = logging.Logger("cmds/files")

var FilesCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Manipulate unixfs files.",
		ShortDescription: `
Files is an API for manipulating IPFS objects as if they were a unix filesystem.

NOTE:
Most of the subcommands of 'ipfs files' accept the '--flush' flag. It defaults to
true. Use caution when setting this flag to false. It will improve performance
for large numbers of file operations, but it does so at the cost of consistency
guarantees. If the daemon is unexpectedly killed before running 'ipfs files flush'
on the files in question, then data may be lost. This also applies to running
'ipfs repo gc' concurrently with '--flush=false' operations.
`,
	},
	Options: []cmds.Option{
		cmds.BoolOption("f", "flush", "Flush target and ancestors after write. Default: true."),
	},
	Subcommands: map[string]*cmds.Command{
		"read":  FilesReadCmd,
		"write": FilesWriteCmd,
		"mv":    FilesMvCmd,
		"cp":    FilesCpCmd,
		"ls":    FilesLsCmd,
		"mkdir": FilesMkdirCmd,
		"stat":  FilesStatCmd,
		"rm":    FilesRmCmd,
		"flush": FilesFlushCmd,
	},
}

var formatError = errors.New("Format was set by multiple options. Only one format option is allowed")

var FilesStatCmd = &cmds.Command{
	Helptext: cmds.HelpText{
		Tagline: "Display file status.",
	},

	Arguments: []cmds.Argument{
		cmds.StringArg("path", true, false, "Path to node to stat."),
	},
	Options: []cmds.Option{
		cmds.StringOption("format", "Print statistics in given format. Allowed tokens: "+
			"<hash> <size> <cumulsize> <type> <childs>. Conflicts with other format options.").Default(
			`<hash>
Size: <size>
CumulativeSize: <cumulsize>
ChildBlocks: <childs>
Type: <type>`),
		cmds.BoolOption("hash", "Print only hash. Implies '--format=<hash>. Conflicts with other format options.").Default(false),
		cmds.BoolOption("size", "Print only size. Implies '--format=<cumulsize>. Conflicts with other format options.").Default(false),
	},
	Run: func(req cmds.Request, res cmds.Response) {

		_, err := statGetFormatOptions(req)
		if err != nil {
			res.SetError(err, cmds.ErrClient)
		}

		node, err := req.InvocContext().GetNode()
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		path, err := checkPath(req.Arguments()[0])
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		fsn, err := mfs.Lookup(node.FilesRoot, path)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		o, err := statNode(node.DAG, fsn)
		if err != nil {
			res.SetError(err, cmds.ErrNormal)
			return
		}

		res.SetOutput(o)
	},
	Marshalers: cmds.MarshalerMap{
		cmds.Text: func(res cmds.Response) (io.Reader, error) {

			out := res.Output().(*Object)
			buf := new(bytes.Buffer)

			s, _ := statGetFormatOptions(res.Request())
			s = strings.Replace(s, "<hash>", out.Hash, -1)
			s = strings.Replace(s, "<size>", fmt.Sprintf("%d", out.Size), -1)
			s = strings.Replace(s, "<cumulsize>", fmt.Sprintf("%d", out.CumulativeSize), -1)
			s = strings.Replace(s, "<childs>", fmt.Sprintf("%d", out.Blocks), -1)
			s = strings.Replace(s, "<type>", out.Type, -1)

			fmt.Fprintln(buf, s)
			return buf, nil
		},
	},
	Type: Object{},
}

func moreThanOne(a, b, c bool) bool {
	return a && b || b && c || a && c
}

func statGetFormatOptions(req cmds.Request) (string, error) {

	hash, _, _ := req.Option("hash").Bool()
	size, _, _ := req.Option("size").Bool()
	format, found, _ := req.Option("format").String()

	if moreThanOne(hash, size, found) {
		return "", formatError
	}

	if hash {
		return "<hash>", nil
	} else if size {
		return "<cumulsize>", nil
	} else {
		return format, nil
	}
}

func statNode(ds dag.DAGService, fsn mfs.FSNode) (*Object, error) {
	nd, err := fsn.GetNode()
	if err != nil {
		return nil, err
	}

	k, err := nd.Key()
	if err != nil {
{'fraction_non_alphanumeric': 0.15622130394857667, 'fraction_numerical': 0.004935720844811754, 'mean_word_length': 3.925381571509327, 'pattern_counts': {'":': 18, '<': 41, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5421397', 'n_tokens_mistral': 3471, 'n_tokens_neox': 3238, 'n_words': 836}