Skip to content

Commit 99a1b96

Browse files
committed
split into multiple files
1 parent f0d0225 commit 99a1b96

5 files changed

Lines changed: 129 additions & 114 deletions

File tree

file_handling.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package main
2+
3+
import (
4+
"io"
5+
"log"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
)
10+
11+
type File struct {
12+
Path string
13+
info os.FileInfo
14+
}
15+
16+
func NewFile(path string) *File {
17+
absPath, err := filepath.Abs(path)
18+
if err != nil {
19+
log.Fatalf("Unable to resolve absolute path of %v: %v", path, err)
20+
}
21+
return &File{Path: absPath}
22+
}
23+
24+
func (f *File) Base() string {
25+
return filepath.Base(f.Path)
26+
}
27+
28+
func (f *File) Dir() string {
29+
return filepath.Dir(f.Path)
30+
}
31+
32+
func (f *File) Info() os.FileInfo {
33+
if f.info == nil {
34+
stat, err := os.Stat(f.Path)
35+
if err != nil {
36+
log.Fatalf("Failed to stat %v: %v", f.Path, err)
37+
}
38+
f.info = stat
39+
}
40+
return f.info
41+
}
42+
43+
func (f *File) Mode() os.FileMode {
44+
return f.Info().Mode()
45+
}
46+
47+
// Read the file into a string.
48+
func (f *File) Read() string {
49+
handle, err := os.Open(f.Path)
50+
if err != nil {
51+
log.Fatalf("Unable to open %v: %v", f.Path, err)
52+
}
53+
defer handle.Close()
54+
builder := new(strings.Builder)
55+
if _, err := io.Copy(builder, handle); err != nil {
56+
log.Fatalf("Failed to read %v to a string: %v", f.Path, err)
57+
}
58+
return builder.String()
59+
}
60+
61+
// Write content to file atomically, by writing it to a temporary file first,
62+
// and then moving it to the destination, overwriting the original.
63+
func (f *File) Write(content string) {
64+
tempName := f.Dir() + string(os.PathSeparator) + RandomString(20)
65+
if err := os.WriteFile(tempName, []byte(content), f.Mode()); err != nil {
66+
log.Fatalf("Error creating tempfile in %v: %v", f.Dir(), err)
67+
}
68+
69+
log.Printf("Rewriting %v", f.Path)
70+
if err := os.Rename(tempName, f.Path); err != nil {
71+
log.Fatalf("Unable to atomically move temp file %v to %v: %v", tempName, f.Path, err)
72+
}
73+
}

find_replace.go

Lines changed: 2 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ package main
22

33
import (
44
"errors"
5-
"io"
65
"log"
76
"math/rand"
87
"os"
9-
"path/filepath"
108
"strings"
119
"time"
1210

@@ -20,42 +18,6 @@ type findReplace struct {
2018
replace string
2119
}
2220

23-
type File struct {
24-
Path string
25-
info os.FileInfo
26-
}
27-
28-
func NewFile(path string) *File {
29-
absPath, err := filepath.Abs(path)
30-
if err != nil {
31-
log.Fatalf("Unable to resolve absolute path of %v: %v", path, err)
32-
}
33-
return &File{Path: absPath}
34-
}
35-
36-
func (f *File) Base() string {
37-
return filepath.Base(f.Path)
38-
}
39-
40-
func (f *File) Dir() string {
41-
return filepath.Dir(f.Path)
42-
}
43-
44-
func (f *File) Info() os.FileInfo {
45-
if f.info == nil {
46-
stat, err := os.Stat(f.Path)
47-
if err != nil {
48-
log.Fatalf("Failed to stat %v: %v", f.Path, err)
49-
}
50-
f.info = stat
51-
}
52-
return f.info
53-
}
54-
55-
func (f *File) Mode() os.FileMode {
56-
return f.Info().Mode()
57-
}
58-
5921
// main processes command line arguments, builds the context struct, and begins
6022
// the process of walking the current working directory.
6123
//
@@ -142,52 +104,9 @@ func (fr *findReplace) RenameFile(f *File) {
142104
// context.
143105
func (fr *findReplace) ReplaceContents(f *File) {
144106
// Find & replace the contents of file.
145-
content := readFile(f.Path)
107+
content := f.Read()
146108
if util.IsText([]byte(content)) && strings.Contains(content, fr.find) {
147109
newContent := strings.Replace(content, fr.find, fr.replace, -1)
148-
writeFile(f, newContent)
149-
}
150-
}
151-
152-
// readFile reads a file at the given path into a string.
153-
func readFile(path string) string {
154-
f, err := os.Open(path)
155-
if err != nil {
156-
log.Fatalf("Unable to open %v: %v", path, err)
157-
}
158-
defer f.Close()
159-
builder := new(strings.Builder)
160-
if _, err := io.Copy(builder, f); err != nil {
161-
log.Fatalf("Failed to read %v to a string: %v", path, err)
162-
}
163-
return builder.String()
164-
}
165-
166-
// writeFile atomically write content to file by writing it to a temporary file
167-
// first, and then moving it to the destination, overwriting the original.
168-
func writeFile(f *File, content string) {
169-
tempName := f.Dir() + string(os.PathSeparator) + randomString(20)
170-
if err := os.WriteFile(tempName, []byte(content), f.Mode()); err != nil {
171-
log.Fatalf("Error creating tempfile in %v: %v", f.Dir(), err)
172-
}
173-
174-
log.Printf("Rewriting %v", f.Path)
175-
if err := os.Rename(tempName, f.Path); err != nil {
176-
log.Fatalf("Unable to atomically move temp file %v to %v: %v", tempName, f.Path, err)
177-
}
178-
}
179-
180-
var characters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
181-
182-
// randomString generates a random base-62 string of the given length (or returns an
183-
// empty string).
184-
func randomString(n int) string {
185-
if n <= 0 {
186-
return ""
187-
}
188-
b := make([]rune, n)
189-
for i := range b {
190-
b[i] = characters[rand.Intn(len(characters))]
110+
f.Write(newContent)
191111
}
192-
return string(b)
193112
}

find_replace_test.go

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func TestHandleFileWithFile(t *testing.T) {
6767
fr.HandleFile(f)
6868
assertPathExistsAfterRename(t, f.Path, expectedPath)
6969

70-
got := readFile(expectedPath)
70+
got := NewFile(expectedPath).Read()
7171
if got != want {
7272
t.Errorf("replace %v with %v in %v, but got %v; want %v", find, replace, initial, got, want)
7373
}
@@ -93,7 +93,7 @@ func TestRenameFile(t *testing.T) {
9393
// assertNewContentsOfFile ensures that the contents of the file at the given
9494
// path exactly match the desired string.
9595
func assertNewContentsOfFile(t *testing.T, path string, initial string, find string, replace string, want string) {
96-
got := readFile(path)
96+
got := NewFile(path).Read()
9797
if got != want {
9898
t.Errorf("replace %v with %v in %v, but got %v; want %v", find, replace, initial, got, want)
9999
}
@@ -163,32 +163,3 @@ func TestReplaceContentsNoMatches(t *testing.T) {
163163
fr.ReplaceContents(f)
164164
assertNewContentsOfFile(t, f.Path, initial, find, replace, want)
165165
}
166-
167-
// assertRandomStringLength ensures that the generated string matches the
168-
// desired length.
169-
func assertRandomStringLength(t *testing.T, ask int, want int) {
170-
got := len(randomString(ask))
171-
if got != want {
172-
t.Errorf("len(RandomString(%v)) = %v; want %v", ask, got, want)
173-
}
174-
}
175-
176-
func TestRandomStringLengthNegativeOne(t *testing.T) {
177-
assertRandomStringLength(t, -1, 0)
178-
}
179-
180-
func TestRandomStringLengthZero(t *testing.T) {
181-
assertRandomStringLength(t, 0, 0)
182-
}
183-
184-
func TestRandomStringLengthOne(t *testing.T) {
185-
assertRandomStringLength(t, 1, 1)
186-
}
187-
188-
func TestRandomStringLengthTen(t *testing.T) {
189-
assertRandomStringLength(t, 10, 10)
190-
}
191-
192-
func TestRandomStringLengthTwenty(t *testing.T) {
193-
assertRandomStringLength(t, 20, 20)
194-
}

strings.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package main
2+
3+
import "math/rand"
4+
5+
var characters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
6+
7+
// randomString generates a random base-62 string of the given length (or returns an
8+
// empty string).
9+
func RandomString(n int) string {
10+
if n <= 0 {
11+
return ""
12+
}
13+
b := make([]rune, n)
14+
for i := range b {
15+
b[i] = characters[rand.Intn(len(characters))]
16+
}
17+
return string(b)
18+
}

strings_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
)
6+
7+
// assertRandomStringLength ensures that the generated string matches the
8+
// desired length.
9+
func assertRandomStringLength(t *testing.T, ask int, want int) {
10+
got := len(RandomString(ask))
11+
if got != want {
12+
t.Errorf("len(RandomString(%v)) = %v; want %v", ask, got, want)
13+
}
14+
}
15+
16+
func TestRandomStringLengthNegativeOne(t *testing.T) {
17+
assertRandomStringLength(t, -1, 0)
18+
}
19+
20+
func TestRandomStringLengthZero(t *testing.T) {
21+
assertRandomStringLength(t, 0, 0)
22+
}
23+
24+
func TestRandomStringLengthOne(t *testing.T) {
25+
assertRandomStringLength(t, 1, 1)
26+
}
27+
28+
func TestRandomStringLengthTen(t *testing.T) {
29+
assertRandomStringLength(t, 10, 10)
30+
}
31+
32+
func TestRandomStringLengthTwenty(t *testing.T) {
33+
assertRandomStringLength(t, 20, 20)
34+
}

0 commit comments

Comments
 (0)