Ejemplo n.º 1
0
func (c *APIDescribeCmd) Execute(args []string) error {
	context, err := prepareCommandContext(c.File)
	if err != nil {
		return err
	}
	file := context.relativeFile
	units, err := getSourceUnitsWithFile(context.buildStore, context.repo, file)
	if err != nil {
		return err
	}

	if GlobalOpt.Verbose {
		if len(units) > 0 {
			ids := make([]string, len(units))
			for i, u := range units {
				ids[i] = string(u.ID())
			}
			log.Printf("Position %s:%d is in %d source units %v.", file, c.StartByte, len(units), ids)
		} else {
			log.Printf("Position %s:%d is not in any source units.", file, c.StartByte)
		}
	}

	// Find the ref(s) at the character position.
	var ref *graph.Ref
	var nearbyRefs []*graph.Ref // Find nearby refs to help with debugging.
OuterLoop:
	for _, u := range units {
		var g graph.Output
		graphFile := plan.SourceUnitDataFilename("graph", u)
		f, err := context.commitFS.Open(graphFile)
		if err != nil {
			return err
		}
		defer f.Close()
		if err := json.NewDecoder(f).Decode(&g); err != nil {
			return fmt.Errorf("%s: %s", graphFile, err)
		}
		for _, ref2 := range g.Refs {
			if file == ref2.File {
				if c.StartByte >= ref2.Start && c.StartByte <= ref2.End {
					ref = ref2
					if ref.DefUnit == "" {
						ref.DefUnit = u.Name
					}
					if ref.DefUnitType == "" {
						ref.DefUnitType = u.Type
					}
					break OuterLoop
				} else if GlobalOpt.Verbose && abs(int(ref2.Start)-int(c.StartByte)) < 25 {
					nearbyRefs = append(nearbyRefs, ref2)
				}
			}
		}
	}

	if ref == nil {
		if GlobalOpt.Verbose {
			log.Printf("No ref found at %s:%d.", file, c.StartByte)

			if len(nearbyRefs) > 0 {
				log.Printf("However, nearby refs were found in the same file:")
				for _, nref := range nearbyRefs {
					log.Printf("Ref at bytes %d-%d to %v", nref.Start, nref.End, nref.DefKey())
				}
			}

			f, err := os.Open(file)
			if err == nil {
				defer f.Close()
				b, err := ioutil.ReadAll(f)
				if err != nil {
					log.Fatalf("Error reading source file: %s.", err)
				}
				start := c.StartByte
				if start < 0 || int(start) > len(b)-1 {
					log.Fatalf("Start byte %d is out of file bounds.", c.StartByte)
				}
				end := c.StartByte + 50
				if int(end) > len(b)-1 {
					end = uint32(len(b) - 1)
				}
				log.Printf("Surrounding source is:\n\n%s", b[start:end])
			} else {
				log.Printf("Error opening source file to show surrounding source: %s.", err)
			}
		}
		fmt.Println(`{}`)
		return nil
	}

	// ref.DefRepo is *not* guaranteed to be non-empty, as
	// repo.URI() will return the empty string if the repo's
	// CloneURL is empty or malformed.
	if ref.DefRepo == "" {
		ref.DefRepo = context.repo.URI()
	}

	var resp apiDescribeCmdOutput
	// Now find the def for this ref.

	defInCurrentRepo := ref.DefRepo == context.repo.URI()
	if defInCurrentRepo {
		// Def is in the current repo.
		var g graph.Output
		graphFile := plan.SourceUnitDataFilename("graph", &unit.SourceUnit{Name: ref.DefUnit, Type: ref.DefUnitType})
		f, err := context.commitFS.Open(graphFile)
		if err != nil {
			return err
		}
		defer f.Close()
		if err := json.NewDecoder(f).Decode(&g); err != nil {
			return fmt.Errorf("%s: %s", graphFile, err)
		}
		for _, def2 := range g.Defs {
			if def2.Path == ref.DefPath {
				resp.Def = &sourcegraph.Def{Def: *def2}
				break
			}
		}
		if resp.Def != nil {
			for _, doc := range g.Docs {
				if doc.Path == ref.DefPath {
					resp.Def.DocHTML = doc.Data
				}
			}

			// If Def is in the current Repo, transform that path to be an absolute path
			resp.Def.File = filepath.Join(context.repo.RootDir, resp.Def.File)
		}
		if resp.Def == nil && GlobalOpt.Verbose {
			log.Printf("No definition found with path %q in unit %q type %q.", ref.DefPath, ref.DefUnit, ref.DefUnitType)
		}
	}

	// spec is only valid for remote requests if ref.DefRepo is
	// non-empty.
	var spec sourcegraph.DefSpec
	var specValid bool
	if ref.DefRepo != "" {
		specValid = true
		spec = sourcegraph.DefSpec{
			Repo:     string(ref.DefRepo),
			UnitType: ref.DefUnitType,
			Unit:     ref.DefUnit,
			Path:     string(ref.DefPath),
		}
	}

	if specValid {
		apiclient := NewAPIClientWithAuthIfPresent()
		var wg sync.WaitGroup
		if resp.Def == nil {
			// Def is not in the current repo. Try looking it up using the
			// Sourcegraph API.
			wg.Add(1)
			go func() {
				defer wg.Done()
				var err error
				resp.Def, _, err = apiclient.Defs.Get(spec, &sourcegraph.DefGetOptions{Doc: true})
				if err != nil && GlobalOpt.Verbose {
					log.Printf("Couldn't fetch definition %v: %s.", spec, err)
				}
			}()
		}

		if !c.NoExamples {
			wg.Add(1)
			go func() {
				defer wg.Done()
				var err error
				resp.Examples, _, err = apiclient.Defs.ListExamples(spec, &sourcegraph.DefListExamplesOptions{
					Formatted:   true,
					ListOptions: sourcegraph.ListOptions{PerPage: 4},
				})
				if err != nil && GlobalOpt.Verbose {
					log.Printf("Couldn't fetch examples for %v: %s.", spec, err)
				}
			}()
		}
		wg.Wait()
	}

	if err := json.NewEncoder(os.Stdout).Encode(resp); err != nil {
		return err
	}
	return nil
}
Ejemplo n.º 2
0
func (c *APIDescribeCmd) Execute(args []string) error {
	context, err := prepareCommandContext(c.File)
	if err != nil {
		return err
	}
	file := context.relativeFile
	units, err := getSourceUnitsWithFile(context.buildStore, context.repo, file)
	if err != nil {
		return err
	}

	if GlobalOpt.Verbose {
		if len(units) > 0 {
			ids := make([]string, len(units))
			for i, u := range units {
				ids[i] = string(u.ID())
			}
			log.Printf("Position %s:%d is in %d source units %v.", file, c.StartByte, len(units), ids)
		} else {
			log.Printf("Position %s:%d is not in any source units.", file, c.StartByte)
		}
	}

	// Find the ref(s) at the character position.
	var ref *graph.Ref
	var nearbyRefs []*graph.Ref // Find nearby refs to help with debugging.
OuterLoop:
	for _, u := range units {
		var g graph.Output
		graphFile := plan.SourceUnitDataFilename("graph", u)
		f, err := context.commitFS.Open(graphFile)
		if err != nil {
			return err
		}
		defer f.Close()
		if err := json.NewDecoder(f).Decode(&g); err != nil {
			return fmt.Errorf("%s: %s", graphFile, err)
		}
		for _, ref2 := range g.Refs {
			if file == ref2.File {
				if c.StartByte >= ref2.Start && c.StartByte <= ref2.End {
					ref = ref2
					if ref.DefUnit == "" {
						ref.DefUnit = u.Name
					}
					if ref.DefUnitType == "" {
						ref.DefUnitType = u.Type
					}
					break OuterLoop
				} else if GlobalOpt.Verbose && abs(int(ref2.Start)-int(c.StartByte)) < 25 {
					nearbyRefs = append(nearbyRefs, ref2)
				}
			}
		}
	}

	if ref == nil {
		if GlobalOpt.Verbose {
			log.Printf("No ref found at %s:%d.", file, c.StartByte)

			if len(nearbyRefs) > 0 {
				log.Printf("However, nearby refs were found in the same file:")
				for _, nref := range nearbyRefs {
					log.Printf("Ref at bytes %d-%d to %v", nref.Start, nref.End, nref.DefKey())
				}
			}

			f, err := os.Open(file)
			if err == nil {
				defer f.Close()
				b, err := ioutil.ReadAll(f)
				if err != nil {
					log.Fatalf("Error reading source file: %s.", err)
				}
				start := c.StartByte
				if start < 0 || int(start) > len(b)-1 {
					log.Fatalf("Start byte %d is out of file bounds.", c.StartByte)
				}
				end := c.StartByte + 50
				if int(end) > len(b)-1 {
					end = uint32(len(b) - 1)
				}
				log.Printf("Surrounding source is:\n\n%s", b[start:end])
			} else {
				log.Printf("Error opening source file to show surrounding source: %s.", err)
			}
		}
		colorable.Println(`{}`)
		return nil
	}

	var resp apiDescribeCmdOutput
	// Now find the def for this ref.

	defInCurrentRepo := ref.DefRepo == ""
	if defInCurrentRepo {
		// Def is in the current repo.
		var g graph.Output
		graphFile := plan.SourceUnitDataFilename("graph", &unit.SourceUnit{Name: ref.DefUnit, Type: ref.DefUnitType})
		f, err := context.commitFS.Open(graphFile)
		if err != nil {
			return err
		}
		defer f.Close()
		if err := json.NewDecoder(f).Decode(&g); err != nil {
			return fmt.Errorf("%s: %s", graphFile, err)
		}
		for _, def := range g.Defs {
			if def.Path == ref.DefPath {
				resp.Def = def
				break
			}
		}
		if resp.Def != nil {
			// If Def is in the current Repo, transform that path to be an absolute path
			resp.Def.File = filepath.ToSlash(filepath.Join(context.repo.RootDir, resp.Def.File))
		}
		if resp.Def == nil && GlobalOpt.Verbose {
			log.Printf("No definition found with path %q in unit %q type %q.", ref.DefPath, ref.DefUnit, ref.DefUnitType)
		}
	}

	if err := json.NewEncoder(os.Stdout).Encode(resp); err != nil {
		return err
	}
	return nil
}