kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/services/cli/command_ls.go (about)

     1  /*
     2   * Copyright 2017 The Kythe Authors. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *   http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cli
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"flag"
    23  	"fmt"
    24  	"path/filepath"
    25  
    26  	"kythe.io/kythe/go/services/filetree"
    27  	"kythe.io/kythe/go/util/kytheuri"
    28  
    29  	ftpb "kythe.io/kythe/proto/filetree_go_proto"
    30  )
    31  
    32  type lsCommand struct {
    33  	baseKytheCommand
    34  	lsURIs         bool
    35  	filesOnly      bool
    36  	dirsOnly       bool
    37  	includeMissing bool
    38  }
    39  
    40  func (lsCommand) Name() string     { return "ls" }
    41  func (lsCommand) Synopsis() string { return "list a directory's contents" }
    42  func (c *lsCommand) SetFlags(flag *flag.FlagSet) {
    43  	flag.BoolVar(&c.lsURIs, "uris", false, "Display files/directories as Kythe URIs")
    44  	flag.BoolVar(&c.filesOnly, "files", false, "Display only files")
    45  	flag.BoolVar(&c.dirsOnly, "dirs", false, "Display only directories")
    46  	flag.BoolVar(&c.includeMissing, "include_files_missing_text", false, "Include files missing text")
    47  }
    48  func (c lsCommand) Run(ctx context.Context, flag *flag.FlagSet, api API) error {
    49  	if c.filesOnly && c.dirsOnly {
    50  		return errors.New("--files and --dirs are mutually exclusive")
    51  	}
    52  
    53  	if len(flag.Args()) == 0 {
    54  		req := &ftpb.CorpusRootsRequest{}
    55  		LogRequest(req)
    56  		cr, err := api.FileTreeService.CorpusRoots(ctx, req)
    57  		if err != nil {
    58  			return err
    59  		}
    60  		return c.displayCorpusRoots(cr)
    61  	}
    62  	var corpus, root, path string
    63  	switch len(flag.Args()) {
    64  	case 1:
    65  		uri, err := kytheuri.Parse(flag.Arg(0))
    66  		if err != nil {
    67  			return fmt.Errorf("invalid uri %q: %v", flag.Arg(0), err)
    68  		}
    69  		corpus = uri.Corpus
    70  		root = uri.Root
    71  		path = uri.Path
    72  	default:
    73  		return fmt.Errorf("too many arguments given: %v", flag.Args())
    74  	}
    75  	path = filetree.CleanDirPath(path)
    76  	req := &ftpb.DirectoryRequest{
    77  		Corpus: corpus,
    78  		Root:   root,
    79  		Path:   path,
    80  
    81  		IncludeFilesMissingText: c.includeMissing,
    82  	}
    83  	LogRequest(req)
    84  	dir, err := api.FileTreeService.Directory(ctx, req)
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	if c.filesOnly {
    90  		dir.Entry = filterEntries(dir.Entry, ftpb.DirectoryReply_FILE)
    91  	} else if c.dirsOnly {
    92  		dir.Entry = filterEntries(dir.Entry, ftpb.DirectoryReply_DIRECTORY)
    93  	}
    94  
    95  	return c.displayDirectory(dir)
    96  }
    97  
    98  func filterEntries(entries []*ftpb.DirectoryReply_Entry, kind ftpb.DirectoryReply_Kind) []*ftpb.DirectoryReply_Entry {
    99  	var j int
   100  	for _, e := range entries {
   101  		if e.Kind == kind {
   102  			entries[j] = e
   103  			j++
   104  		}
   105  	}
   106  	return entries[:j]
   107  }
   108  
   109  func (c lsCommand) displayCorpusRoots(cr *ftpb.CorpusRootsReply) error {
   110  	if DisplayJSON {
   111  		return PrintJSONMessage(cr)
   112  	}
   113  
   114  	for _, corpus := range cr.Corpus {
   115  		for _, root := range corpus.Root {
   116  			var err error
   117  			if c.lsURIs {
   118  				uri := kytheuri.URI{
   119  					Corpus: corpus.Name,
   120  					Root:   root,
   121  				}
   122  				_, err = fmt.Fprintln(out, uri.String())
   123  			} else {
   124  				_, err = fmt.Fprintln(out, filepath.Join(corpus.Name, root))
   125  			}
   126  			if err != nil {
   127  				return err
   128  			}
   129  		}
   130  	}
   131  	return nil
   132  }
   133  
   134  func (c lsCommand) displayDirectory(d *ftpb.DirectoryReply) error {
   135  	if DisplayJSON {
   136  		return PrintJSONMessage(d)
   137  	}
   138  
   139  	for _, e := range d.Entry {
   140  		name := e.Name
   141  		if c.lsURIs {
   142  			uri := &kytheuri.URI{
   143  				Corpus: d.Corpus,
   144  				Root:   d.Root,
   145  				Path:   filepath.Join(d.Path, name),
   146  			}
   147  			name = uri.String()
   148  		} else if e.Kind == ftpb.DirectoryReply_DIRECTORY {
   149  			name += "/"
   150  		}
   151  
   152  		if _, err := fmt.Fprintln(out, name); err != nil {
   153  			return err
   154  		}
   155  	}
   156  	return nil
   157  }