Skip to content

Commit 3d8fdd7

Browse files
Fix issue #8: Multi path input for output compilation (#13)
Co-authored-by: openhands <[email protected]>
1 parent c424f22 commit 3d8fdd7

File tree

4 files changed

+204
-116
lines changed

4 files changed

+204
-116
lines changed

cmd/multi_path_test.go

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package cmd
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
"testing"
10+
)
11+
12+
func TestMultiPathInput(t *testing.T) {
13+
// Create temporary directories for test repositories
14+
tempDir1, err := os.MkdirTemp("", "repo1")
15+
if err != nil {
16+
t.Fatalf("Failed to create temp directory: %v", err)
17+
}
18+
defer os.RemoveAll(tempDir1)
19+
20+
tempDir2, err := os.MkdirTemp("", "repo2")
21+
if err != nil {
22+
t.Fatalf("Failed to create temp directory: %v", err)
23+
}
24+
defer os.RemoveAll(tempDir2)
25+
26+
// Create test files in the first repository
27+
file1Path := filepath.Join(tempDir1, "file1.txt")
28+
err = os.WriteFile(file1Path, []byte("Content of file1"), 0644)
29+
if err != nil {
30+
t.Fatalf("Failed to write test file: %v", err)
31+
}
32+
33+
// Create test files in the second repository
34+
file2Path := filepath.Join(tempDir2, "file2.txt")
35+
err = os.WriteFile(file2Path, []byte("Content of file2"), 0644)
36+
if err != nil {
37+
t.Fatalf("Failed to write test file: %v", err)
38+
}
39+
40+
// Capture stdout
41+
oldStdout := os.Stdout
42+
r, w, _ := os.Pipe()
43+
os.Stdout = w
44+
45+
// Set up command line arguments
46+
oldArgs := os.Args
47+
os.Args = []string{"git2gpt", tempDir1, tempDir2}
48+
49+
// Execute the command
50+
Execute()
51+
52+
// Restore stdout and args
53+
w.Close()
54+
os.Stdout = oldStdout
55+
os.Args = oldArgs
56+
57+
// Read captured output
58+
var buf bytes.Buffer
59+
io.Copy(&buf, r)
60+
output := buf.String()
61+
62+
// Verify that both files are included in the output
63+
if !strings.Contains(output, "file1.txt") || !strings.Contains(output, "Content of file1") {
64+
t.Errorf("Output does not contain content from the first repository")
65+
}
66+
if !strings.Contains(output, "file2.txt") || !strings.Contains(output, "Content of file2") {
67+
t.Errorf("Output does not contain content from the second repository")
68+
}
69+
}

cmd/root.go

+133-116
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package cmd
22

33
import (
4-
"fmt"
5-
"os"
4+
"fmt"
5+
"os"
66

7-
"github.com/chand1012/git2gpt/prompt"
8-
"github.com/spf13/cobra"
7+
"github.com/chand1012/git2gpt/prompt"
8+
"github.com/spf13/cobra"
99
)
1010

1111
var repoPath string
@@ -20,122 +20,139 @@ var debug bool
2020
var scrubComments bool
2121

2222
var rootCmd = &cobra.Command{
23-
Use: "git2gpt [flags] /path/to/git/repository",
24-
Short: "git2gpt is a utility to convert a Git repository to a text file for input into GPT-4",
25-
Args: cobra.ExactArgs(1),
26-
Run: func(cmd *cobra.Command, args []string) {
27-
repoPath = args[0]
28-
ignoreList := prompt.GenerateIgnoreList(repoPath, ignoreFilePath, !ignoreGitignore)
29-
repo, err := prompt.ProcessGitRepo(repoPath, ignoreList)
30-
if err != nil {
31-
fmt.Printf("Error: %s\n", err)
32-
os.Exit(1)
33-
}
34-
if outputJSON {
35-
output, err := prompt.MarshalRepo(repo, scrubComments)
36-
if err != nil {
37-
fmt.Printf("Error: %s\n", err)
38-
os.Exit(1)
39-
}
40-
if outputFile != "" {
41-
// if output file exists, throw error
42-
if _, err := os.Stat(outputFile); err == nil {
43-
fmt.Printf("Error: output file %s already exists\n", outputFile)
44-
os.Exit(1)
45-
}
46-
err = os.WriteFile(outputFile, []byte(output), 0644)
47-
if err != nil {
48-
fmt.Printf("Error: could not write to output file %s\n", outputFile)
49-
os.Exit(1)
50-
}
51-
} else {
52-
if !debug {
53-
fmt.Println(string(output))
54-
}
55-
}
56-
return
57-
}
58-
if outputXML {
59-
output, err := prompt.OutputGitRepoXML(repo, scrubComments)
60-
if err != nil {
61-
fmt.Printf("Error: %s\n", err)
62-
os.Exit(1)
63-
}
64-
65-
// Validate the XML output
66-
if err := prompt.ValidateXML(output); err != nil {
67-
fmt.Printf("Error: %s\n", err)
68-
os.Exit(1)
69-
}
70-
71-
if outputFile != "" {
72-
// if output file exists, throw error
73-
if _, err := os.Stat(outputFile); err == nil {
74-
fmt.Printf("Error: output file %s already exists\n", outputFile)
75-
os.Exit(1)
76-
}
77-
err = os.WriteFile(outputFile, []byte(output), 0644)
78-
if err != nil {
79-
fmt.Printf("Error: could not write to output file %s\n", outputFile)
80-
os.Exit(1)
81-
}
82-
} else {
83-
if !debug {
84-
fmt.Println(output)
85-
}
86-
}
87-
return
88-
}
89-
output, err := prompt.OutputGitRepo(repo, preambleFile, scrubComments)
90-
if err != nil {
91-
fmt.Printf("Error: %s\n", err)
92-
os.Exit(1)
93-
}
94-
if outputFile != "" {
95-
// if output file exists, throw error
96-
if _, err := os.Stat(outputFile); err == nil {
97-
fmt.Printf("Error: output file %s already exists\n", outputFile)
98-
os.Exit(1)
99-
}
100-
err = os.WriteFile(outputFile, []byte(output), 0644)
101-
if err != nil {
102-
fmt.Printf("Error: could not write to output file %s\n", outputFile)
103-
os.Exit(1)
104-
}
105-
} else {
106-
if !debug {
107-
fmt.Println(output)
108-
}
109-
}
110-
if estimateTokens {
111-
fmt.Printf("Estimated number of tokens: %d\n", prompt.EstimateTokens(output))
112-
}
113-
},
23+
Use: "git2gpt [flags] /path/to/git/repository [/path/to/another/repository ...]",
24+
Short: "git2gpt is a utility to convert one or more Git repositories to a text file for input into GPT-4",
25+
Args: cobra.MinimumNArgs(1),
26+
Run: func(cmd *cobra.Command, args []string) {
27+
// Create a combined repository to hold all files
28+
combinedRepo := &prompt.GitRepo{
29+
Files: []prompt.GitFile{},
30+
}
31+
32+
// Process each repository path
33+
for _, path := range args {
34+
repoPath = path
35+
ignoreList := prompt.GenerateIgnoreList(repoPath, ignoreFilePath, !ignoreGitignore)
36+
repo, err := prompt.ProcessGitRepo(repoPath, ignoreList)
37+
if err != nil {
38+
fmt.Printf("Error processing %s: %s\n", repoPath, err)
39+
os.Exit(1)
40+
}
41+
42+
// Add files from this repo to the combined repo
43+
combinedRepo.Files = append(combinedRepo.Files, repo.Files...)
44+
}
45+
46+
// Update the file count
47+
combinedRepo.FileCount = len(combinedRepo.Files)
48+
if outputJSON {
49+
output, err := prompt.MarshalRepo(combinedRepo, scrubComments)
50+
if err != nil {
51+
fmt.Printf("Error: %s\n", err)
52+
os.Exit(1)
53+
}
54+
if outputFile != "" {
55+
// if output file exists, throw error
56+
if _, err := os.Stat(outputFile); err == nil {
57+
fmt.Printf("Error: output file %s already exists\n", outputFile)
58+
os.Exit(1)
59+
}
60+
err = os.WriteFile(outputFile, []byte(output), 0644)
61+
if err != nil {
62+
fmt.Printf("Error: could not write to output file %s\n", outputFile)
63+
os.Exit(1)
64+
}
65+
} else {
66+
if !debug {
67+
fmt.Println(string(output))
68+
}
69+
}
70+
return
71+
}
72+
if outputXML {
73+
output, err := prompt.OutputGitRepoXML(combinedRepo, scrubComments)
74+
if err != nil {
75+
fmt.Printf("Error: %s\n", err)
76+
os.Exit(1)
77+
}
78+
79+
// Validate the XML output
80+
if err := prompt.ValidateXML(output); err != nil {
81+
fmt.Printf("Error: %s\n", err)
82+
os.Exit(1)
83+
}
84+
85+
if outputFile != "" {
86+
// if output file exists, throw error
87+
if _, err := os.Stat(outputFile); err == nil {
88+
fmt.Printf("Error: output file %s already exists\n", outputFile)
89+
os.Exit(1)
90+
}
91+
err = os.WriteFile(outputFile, []byte(output), 0644)
92+
if err != nil {
93+
fmt.Printf("Error: could not write to output file %s\n", outputFile)
94+
os.Exit(1)
95+
}
96+
} else {
97+
if !debug {
98+
fmt.Println(output)
99+
}
100+
}
101+
return
102+
}
103+
output, err := prompt.OutputGitRepo(combinedRepo, preambleFile, scrubComments)
104+
if err != nil {
105+
fmt.Printf("Error: %s\n", err)
106+
os.Exit(1)
107+
}
108+
if outputFile != "" {
109+
// if output file exists, throw error
110+
if _, err := os.Stat(outputFile); err == nil {
111+
fmt.Printf("Error: output file %s already exists\n", outputFile)
112+
os.Exit(1)
113+
}
114+
err = os.WriteFile(outputFile, []byte(output), 0644)
115+
if err != nil {
116+
fmt.Printf("Error: could not write to output file %s\n", outputFile)
117+
os.Exit(1)
118+
}
119+
} else {
120+
if !debug {
121+
fmt.Println(output)
122+
}
123+
}
124+
if estimateTokens {
125+
fmt.Printf("Estimated number of tokens: %d\n", prompt.EstimateTokens(output))
126+
}
127+
},
114128
}
115129

116130
func init() {
117-
rootCmd.Flags().StringVarP(&preambleFile, "preamble", "p", "", "path to preamble text file")
118-
// output to file flag. Should be a string
119-
rootCmd.Flags().StringVarP(&outputFile, "output", "o", "", "path to output file")
120-
// estimate tokens. Should be a bool
121-
rootCmd.Flags().BoolVarP(&estimateTokens, "estimate", "e", false, "estimate the number of tokens in the output")
122-
// ignore file path. Should be a string
123-
rootCmd.Flags().StringVarP(&ignoreFilePath, "ignore", "i", "", "path to .gptignore file")
124-
// ignore gitignore. Should be a bool
125-
rootCmd.Flags().BoolVarP(&ignoreGitignore, "ignore-gitignore", "g", false, "ignore .gitignore file")
126-
// output JSON. Should be a bool
127-
rootCmd.Flags().BoolVarP(&outputJSON, "json", "j", false, "output JSON")
128-
// output XML. Should be a bool
129-
rootCmd.Flags().BoolVarP(&outputXML, "xml", "x", false, "output XML")
130-
// debug. Should be a bool
131-
rootCmd.Flags().BoolVarP(&debug, "debug", "d", false, "debug mode. Do not output to standard output")
132-
// scrub comments. Should be a bool
133-
rootCmd.Flags().BoolVarP(&scrubComments, "scrub-comments", "s", false, "scrub comments from the output. Decreases token count")
131+
rootCmd.Flags().StringVarP(&preambleFile, "preamble", "p", "", "path to preamble text file")
132+
// output to file flag. Should be a string
133+
rootCmd.Flags().StringVarP(&outputFile, "output", "o", "", "path to output file")
134+
// estimate tokens. Should be a bool
135+
rootCmd.Flags().BoolVarP(&estimateTokens, "estimate", "e", false, "estimate the number of tokens in the output")
136+
// ignore file path. Should be a string
137+
rootCmd.Flags().StringVarP(&ignoreFilePath, "ignore", "i", "", "path to .gptignore file")
138+
// ignore gitignore. Should be a bool
139+
rootCmd.Flags().BoolVarP(&ignoreGitignore, "ignore-gitignore", "g", false, "ignore .gitignore file")
140+
// output JSON. Should be a bool
141+
rootCmd.Flags().BoolVarP(&outputJSON, "json", "j", false, "output JSON")
142+
// output XML. Should be a bool
143+
rootCmd.Flags().BoolVarP(&outputXML, "xml", "x", false, "output XML")
144+
// debug. Should be a bool
145+
rootCmd.Flags().BoolVarP(&debug, "debug", "d", false, "debug mode. Do not output to standard output")
146+
// scrub comments. Should be a bool
147+
rootCmd.Flags().BoolVarP(&scrubComments, "scrub-comments", "s", false, "scrub comments from the output. Decreases token count")
148+
149+
// Update the example usage to show multiple paths
150+
rootCmd.Example = " git2gpt /path/to/repo1 /path/to/repo2\n git2gpt -o output.txt /path/to/repo1 /path/to/repo2"
134151
}
135152

136153
func Execute() {
137-
if err := rootCmd.Execute(); err != nil {
138-
fmt.Println(err)
139-
os.Exit(1)
140-
}
154+
if err := rootCmd.Execute(); err != nil {
155+
fmt.Println(err)
156+
os.Exit(1)
157+
}
141158
}

test_repo1/file1.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Test file 1

test_repo2/file2.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Test file 2

0 commit comments

Comments
 (0)