github.com/tomwright/dasel@v1.27.3/internal/command/select.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "github.com/spf13/cobra" 6 "github.com/tomwright/dasel" 7 "github.com/tomwright/dasel/storage" 8 "io" 9 "reflect" 10 ) 11 12 type selectOptions struct { 13 File string 14 Parser string 15 ReadParser string 16 WriteParser string 17 Selector string 18 Reader io.Reader 19 Writer io.Writer 20 Multi bool 21 NullValueNotFound bool 22 Compact bool 23 DisplayLength bool 24 MergeInputDocuments bool 25 FormatTemplate string 26 Colourise bool 27 EscapeHTML bool 28 } 29 30 func outputNodeLength(writer io.Writer, nodes ...*dasel.Node) error { 31 for _, n := range nodes { 32 val := n.Value 33 if val.Kind() == reflect.Interface { 34 val = val.Elem() 35 } 36 length := 0 37 switch val.Kind() { 38 case reflect.Map, reflect.Slice, reflect.String: 39 length = val.Len() 40 default: 41 length = len(fmt.Sprint(val.Interface())) 42 } 43 if _, err := fmt.Fprintf(writer, "%d\n", length); err != nil { 44 return err 45 } 46 } 47 return nil 48 } 49 50 func runSelectMultiCommand(cmd *cobra.Command, rootNode *dasel.Node, opts selectOptions, writeParser storage.WriteParser, writeOptions []storage.ReadWriteOption) error { 51 var results []*dasel.Node 52 var err error 53 if opts.Selector == "." { 54 results = []*dasel.Node{rootNode} 55 } else { 56 results, err = rootNode.QueryMultiple(opts.Selector) 57 } 58 59 written, err := customErrorHandling(customErrorHandlingOpts{ 60 File: opts.File, 61 Writer: opts.Writer, 62 Err: err, 63 Cmd: cmd, 64 NullFlag: opts.NullValueNotFound, 65 }) 66 if err != nil { 67 return fmt.Errorf("could not query multiple node: %w", err) 68 } 69 if written { 70 return nil 71 } 72 73 if opts.DisplayLength { 74 return outputNodeLength(opts.Writer, results...) 75 } 76 77 if err := writeNodesToOutput(writeNodesToOutputOpts{ 78 Nodes: results, 79 Parser: writeParser, 80 Writer: opts.Writer, 81 FormatTemplate: opts.FormatTemplate, 82 }, cmd, writeOptions...); err != nil { 83 return fmt.Errorf("could not write output: %w", err) 84 } 85 return nil 86 } 87 88 func runSelectCommand(opts selectOptions, cmd *cobra.Command) error { 89 readParser, err := getReadParser(opts.File, opts.ReadParser, opts.Parser) 90 if err != nil { 91 return err 92 } 93 rootNode, err := getRootNode(getRootNodeOpts{ 94 File: opts.File, 95 Parser: readParser, 96 Reader: opts.Reader, 97 MergeInputDocuments: opts.MergeInputDocuments, 98 }, cmd) 99 if err != nil { 100 return err 101 } 102 103 if !rootNode.Value.IsValid() { 104 rootNode = dasel.New(&storage.BasicSingleDocument{ 105 Value: map[string]interface{}{}, 106 }) 107 } 108 109 if opts.Writer == nil { 110 opts.Writer = cmd.OutOrStdout() 111 } 112 113 writeParser, err := getWriteParser(readParser, opts.WriteParser, opts.Parser, "-", opts.File, opts.FormatTemplate) 114 if err != nil { 115 return err 116 } 117 118 writeOptions := []storage.ReadWriteOption{ 119 storage.EscapeHTMLOption(opts.EscapeHTML), 120 } 121 122 if opts.Compact { 123 writeOptions = append(writeOptions, storage.PrettyPrintOption(false)) 124 } 125 if opts.Colourise { 126 writeOptions = append(writeOptions, storage.ColouriseOption(true)) 127 } 128 129 if opts.Multi { 130 return runSelectMultiCommand(cmd, rootNode, opts, writeParser, writeOptions) 131 } 132 133 var res *dasel.Node 134 135 if opts.Selector == "." { 136 res = rootNode 137 } else { 138 res, err = rootNode.Query(opts.Selector) 139 if err != nil { 140 err = fmt.Errorf("could not query node: %w", err) 141 } 142 } 143 144 written, err := customErrorHandling(customErrorHandlingOpts{ 145 File: opts.File, 146 Writer: opts.Writer, 147 Err: err, 148 Cmd: cmd, 149 NullFlag: opts.NullValueNotFound, 150 }) 151 if err != nil { 152 return err 153 } 154 if written { 155 return nil 156 } 157 158 if opts.DisplayLength { 159 return outputNodeLength(opts.Writer, res) 160 } 161 162 if err := writeNodeToOutput(writeNodeToOutputOpts{ 163 Node: res, 164 Parser: writeParser, 165 Writer: opts.Writer, 166 FormatTemplate: opts.FormatTemplate, 167 }, cmd, writeOptions...); err != nil { 168 return fmt.Errorf("could not write output: %w", err) 169 } 170 171 return nil 172 } 173 174 func selectCommand() *cobra.Command { 175 var fileFlag, selectorFlag, parserFlag, readParserFlag, writeParserFlag, formatTemplateFlag string 176 var plainFlag, multiFlag, nullValueNotFoundFlag, compactFlag, lengthFlag, mergeInputDocumentsFlag, 177 colourFlag, colorFlag, escapeHTMLFlag bool 178 179 cmd := &cobra.Command{ 180 Use: "select -f <file> -p <json,yaml,toml,xml,csv> <selector>", 181 Short: "Select properties from the given file.", 182 RunE: func(cmd *cobra.Command, args []string) error { 183 if selectorFlag == "" && len(args) > 0 { 184 selectorFlag = args[0] 185 args = args[1:] 186 } 187 if plainFlag { 188 writeParserFlag = "-" 189 } 190 return runSelectCommand(selectOptions{ 191 File: fileFlag, 192 Parser: parserFlag, 193 ReadParser: readParserFlag, 194 WriteParser: writeParserFlag, 195 Selector: selectorFlag, 196 Multi: multiFlag, 197 NullValueNotFound: nullValueNotFoundFlag, 198 Compact: compactFlag, 199 DisplayLength: lengthFlag, 200 MergeInputDocuments: mergeInputDocumentsFlag, 201 FormatTemplate: formatTemplateFlag, 202 Colourise: colourFlag || colorFlag, 203 EscapeHTML: escapeHTMLFlag, 204 }, cmd) 205 }, 206 } 207 208 cmd.Flags().StringVarP(&fileFlag, "file", "f", "", "The file to query.") 209 cmd.Flags().StringVarP(&selectorFlag, "selector", "s", "", "The selector to use when querying the data structure.") 210 cmd.Flags().StringVarP(&parserFlag, "parser", "p", "", "Shorthand for -r FORMAT -w FORMAT.") 211 cmd.Flags().StringVarP(&readParserFlag, "read", "r", "", "The parser to use when reading.") 212 cmd.Flags().StringVarP(&writeParserFlag, "write", "w", "", "The parser to use when writing.") 213 cmd.Flags().BoolVar(&plainFlag, "plain", false, "Alias of -w plain") 214 cmd.Flags().BoolVarP(&multiFlag, "multiple", "m", false, "Select multiple results.") 215 cmd.Flags().BoolVarP(&nullValueNotFoundFlag, "null", "n", false, "Output null instead of value not found errors.") 216 cmd.Flags().BoolVar(&lengthFlag, "length", false, "Output the length of the selected value.") 217 cmd.Flags().BoolVar(&mergeInputDocumentsFlag, "merge-input-documents", false, "Merge multiple input documents into an array.") 218 cmd.Flags().BoolVarP(&compactFlag, "compact", "c", false, "Compact the output by removing all pretty-printing where possible.") 219 cmd.Flags().StringVar(&formatTemplateFlag, "format", "", "Formatting template to use when writing results.") 220 cmd.Flags().BoolVar(&colourFlag, "colour", false, "Print colourised output.") 221 cmd.Flags().BoolVar(&colorFlag, "color", false, "Alias of --colour.") 222 cmd.Flags().BoolVar(&escapeHTMLFlag, "escape-html", false, "Escape HTML tags when writing output.") 223 224 _ = cmd.MarkFlagFilename("file") 225 226 return cmd 227 }