diff --git a/filewriter.go b/filewriter.go new file mode 100644 index 0000000..c42b3c3 --- /dev/null +++ b/filewriter.go @@ -0,0 +1,43 @@ +package files + +import ( + "fmt" + "io" + "os" + "path/filepath" +) + +// WriteTo writes the given node to the local filesystem at fpath. +func WriteTo(nd Node, fpath string) error { + switch nd := nd.(type) { + case *Symlink: + return os.Symlink(nd.Target, fpath) + case File: + f, err := os.Create(fpath) + defer f.Close() + if err != nil { + return err + } + _, err = io.Copy(f, nd) + if err != nil { + return err + } + return nil + case Directory: + err := os.Mkdir(fpath, 0777) + if err != nil { + return err + } + + entries := nd.Entries() + for entries.Next() { + child := filepath.Join(fpath, entries.Name()) + if err := WriteTo(entries.Node(), child); err != nil { + return err + } + } + return entries.Err() + default: + return fmt.Errorf("file type %T at %q is not supported", nd, fpath) + } +} diff --git a/filewriter_test.go b/filewriter_test.go new file mode 100644 index 0000000..d80ac91 --- /dev/null +++ b/filewriter_test.go @@ -0,0 +1,74 @@ +package files + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +func TestWriteTo(t *testing.T) { + sf := NewMapDirectory(map[string]Node{ + "1": NewBytesFile([]byte("Some text!\n")), + "2": NewBytesFile([]byte("beep")), + "3": NewMapDirectory(nil), + "4": NewBytesFile([]byte("boop")), + "5": NewMapDirectory(map[string]Node{ + "a": NewBytesFile([]byte("foobar")), + }), + }) + tmppath, err := ioutil.TempDir("", "files-test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmppath) + + path := tmppath + "/output" + + err = WriteTo(sf, path) + if err != nil { + t.Fatal(err) + } + expected := map[string]string{ + ".": "", + "1": "Some text!\n", + "2": "beep", + "3": "", + "4": "boop", + "5": "", + "5/a": "foobar", + } + err = filepath.Walk(path, func(cpath string, info os.FileInfo, err error) error { + rpath, err := filepath.Rel(path, cpath) + if err != nil { + return err + } + data, ok := expected[rpath] + if !ok { + return fmt.Errorf("expected something at %q", rpath) + } + delete(expected, rpath) + + if info.IsDir() { + if data != "" { + return fmt.Errorf("expected a directory at %q", rpath) + } + } else { + actual, err := ioutil.ReadFile(cpath) + if err != nil { + return err + } + if string(actual) != data { + return fmt.Errorf("expected %q, got %q", data, string(actual)) + } + } + return nil + }) + if err != nil { + t.Fatal(err) + } + if len(expected) > 0 { + t.Fatalf("failed to find: %#v", expected) + } +}