mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-04-30 03:50:39 +00:00
⬆️ version bump to v4.5
- Update obioptions.Version from "Release 4.4.29" to "/v/ Release v5" - Update version.txt from 4.29 → .30 (automated by Makefile)
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
//go:build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Reference struct {
|
||||
File string `json:"file"`
|
||||
Line int `json:"line"`
|
||||
Column int `json:"column"`
|
||||
Key string `json:"key"`
|
||||
Function string `json:"function"`
|
||||
Context string `json:"context"`
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Method string `json:"method"`
|
||||
Signature string `json:"signature"`
|
||||
Definition string `json:"definition"`
|
||||
References []Reference `json:"references"`
|
||||
Total int `json:"total"`
|
||||
}
|
||||
|
||||
var basePath = "/Users/coissac/Sync/travail/__MOI__/GO/obitools4"
|
||||
|
||||
func main() {
|
||||
cmd := exec.Command("rg", "-n", `\.SetAttribute\(`, basePath+"/pkg", "--type", "go")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error running rg: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
lines := strings.Split(string(output), "\n")
|
||||
lineRe := regexp.MustCompile(`^(.+?):(\d+):\s*(.+)$`)
|
||||
keyRe := regexp.MustCompile(`SetAttribute\("([^"]+)"`)
|
||||
templateKeyRe := regexp.MustCompile(`SetAttribute\("([^"]+)[^"]*"\s*,`)
|
||||
|
||||
var refs []Reference
|
||||
seen := make(map[string]bool)
|
||||
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
matches := lineRe.FindStringSubmatch(line)
|
||||
if matches == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
file := matches[1]
|
||||
lineNum, _ := strconv.Atoi(matches[2])
|
||||
context := strings.TrimSpace(matches[3])
|
||||
|
||||
// Skip definition
|
||||
if strings.Contains(file, "obiseq/attributes.go") && lineNum == 132 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Extract key
|
||||
var key string
|
||||
if keyMatches := keyRe.FindStringSubmatch(context); keyMatches != nil {
|
||||
key = keyMatches[1]
|
||||
} else if tmplMatches := templateKeyRe.FindStringSubmatch(context); tmplMatches != nil {
|
||||
key = tmplMatches[1]
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get function name using treesitter
|
||||
funcName := getFunctionNameTreesitter(file, lineNum)
|
||||
|
||||
uniqueKey := fmt.Sprintf("%s:%d", file, lineNum)
|
||||
if seen[uniqueKey] {
|
||||
continue
|
||||
}
|
||||
seen[uniqueKey] = true
|
||||
|
||||
refs = append(refs, Reference{
|
||||
File: filepath.Base(file),
|
||||
Line: lineNum,
|
||||
Column: 0,
|
||||
Key: key,
|
||||
Function: funcName,
|
||||
Context: context,
|
||||
})
|
||||
}
|
||||
|
||||
sort.Slice(refs, func(i, j int) bool {
|
||||
if refs[i].File != refs[j].File {
|
||||
return refs[i].File < refs[j].File
|
||||
}
|
||||
return refs[i].Line < refs[j].Line
|
||||
})
|
||||
|
||||
result := Result{
|
||||
Method: "SetAttribute",
|
||||
Signature: "func (s *BioSequence) SetAttribute(key string, value interface{})",
|
||||
Definition: basePath + "/pkg/obiseq/attributes.go:132",
|
||||
References: refs,
|
||||
Total: len(refs),
|
||||
}
|
||||
|
||||
outputJSON, err := json.MarshalIndent(result, "", " ")
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Error marshaling JSON: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Println(string(outputJSON))
|
||||
}
|
||||
|
||||
// getFunctionNameTreesitter uses the treesitter_cursor_walk tool to get the containing function
|
||||
func getFunctionNameTreesitter(file string, targetLine int) string {
|
||||
// Convert to 0-based for treesitter
|
||||
row := targetLine - 1
|
||||
|
||||
// Use treesitter cursor walk to get ancestors
|
||||
cmd := exec.Command("bash", "-c",
|
||||
fmt.Sprintf(`kilo treesitter_cursor_walk --file_path %q --row %d --column 0 --max_depth 10 2>/dev/null`, file, row))
|
||||
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
return findContainingFunction(file, targetLine)
|
||||
}
|
||||
|
||||
// Parse the JSON output to find function_declaration or method_declaration
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(output, &result); err != nil {
|
||||
return findContainingFunction(file, targetLine)
|
||||
}
|
||||
|
||||
// Check ancestors for function declaration
|
||||
if ancestors, ok := result["ancestors"].([]interface{}); ok {
|
||||
for _, a := range ancestors {
|
||||
if anc, ok := a.(map[string]interface{}); ok {
|
||||
nodeType, _ := anc["type"].(string)
|
||||
if nodeType == "function_declaration" || nodeType == "method_declaration" {
|
||||
// Try to get the function name from children
|
||||
if children, ok := anc["children"].([]interface{}); ok {
|
||||
for _, c := range children {
|
||||
if child, ok := c.(map[string]interface{}); ok {
|
||||
childType, _ := child["type"].(string)
|
||||
if childType == "identifier" {
|
||||
if text, ok := child["text"].(string); ok {
|
||||
return text
|
||||
}
|
||||
}
|
||||
if childType == "field_identifier" {
|
||||
if text, ok := child["text"].(string); ok {
|
||||
return text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if nodeType == "func_literal" {
|
||||
return "closure"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return findContainingFunction(file, targetLine)
|
||||
}
|
||||
|
||||
func findContainingFunction(file string, targetLine int) string {
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
lines := strings.Split(string(data), "\n")
|
||||
|
||||
for i := targetLine - 1; i >= 0 && i >= targetLine-200; i-- {
|
||||
if i >= len(lines) {
|
||||
continue
|
||||
}
|
||||
line := strings.TrimSpace(lines[i])
|
||||
|
||||
if line == "}" && i > 0 {
|
||||
for j := i - 1; j >= 0 && j >= i-50; j-- {
|
||||
if j >= len(lines) {
|
||||
continue
|
||||
}
|
||||
funcLine := strings.TrimSpace(lines[j])
|
||||
if strings.HasPrefix(funcLine, "func ") {
|
||||
if match := regexp.MustCompile(`func\s+\([^)]+\)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(`).FindStringSubmatch(funcLine); match != nil {
|
||||
return match[1]
|
||||
}
|
||||
if match := regexp.MustCompile(`func\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(`).FindStringSubmatch(funcLine); match != nil {
|
||||
return match[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.HasPrefix(line, "func ") {
|
||||
if match := regexp.MustCompile(`func\s+\([^)]+\)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(`).FindStringSubmatch(line); match != nil {
|
||||
return match[1]
|
||||
}
|
||||
if match := regexp.MustCompile(`func\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(`).FindStringSubmatch(line); match != nil {
|
||||
return match[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#!/bin/bash
|
||||
|
||||
basePath="/Users/coissac/Sync/travail/__MOI__/GO/obitools4"
|
||||
OUTPUT_FILE="${1:-/dev/stdout}"
|
||||
|
||||
# Get all SetAttribute calls
|
||||
rg -n '\.SetAttribute\(' "$basePath/pkg" --type go | while read -r line; do
|
||||
file="${line%%:*}"
|
||||
line_num="${line%:*}"
|
||||
line_num="${line_num##*:}"
|
||||
context="${line##*: }"
|
||||
|
||||
# Extract key (only literal strings)
|
||||
key=$(echo "$context" | sed -n 's/.*SetAttribute("\([^"]*\)".*/\1/p')
|
||||
[ -z "$key" ] && continue
|
||||
|
||||
# Get function name using treesitter
|
||||
func=$(kilo treesitter_cursor_walk \
|
||||
--file_path "$file" \
|
||||
--row "$((line_num - 1))" \
|
||||
--column 0 \
|
||||
--max_depth 10 2>/dev/null |
|
||||
jq -r '.ancestors[] | select(.type == "function_declaration" or .type == "method_declaration") | .children[] | select(.type == "identifier" or .type == "field_identifier") | .text' 2>/dev/null)
|
||||
|
||||
# Fallback to func_literal for closures
|
||||
if [ -z "$func" ]; then
|
||||
func=$(kilo treesitter_cursor_walk \
|
||||
--file_path "$file" \
|
||||
--row "$((line_num - 1))" \
|
||||
--column 0 \
|
||||
--max_depth 10 2>/dev/null |
|
||||
jq -r '.ancestors[] | select(.type == "func_literal") | "closure"' 2>/dev/null)
|
||||
fi
|
||||
|
||||
echo "$(basename "$file")|$line_num|$key|${func:-unknown}|$context"
|
||||
done | sort -t'|' -k1,1 -k2,2n
|
||||
Reference in New Issue
Block a user