11package installer
22
33import (
4+ "bytes"
45 "io"
6+ "io/ioutil"
57 "os"
68
79 "go.evanpurkhiser.com/dots/config"
810 "go.evanpurkhiser.com/dots/resolver"
911)
1012
11- // mustCompile indicates if a dotfile msut be compiled, or if a single-source
12- // dotfile does not require any transformations and may be directly installed.
13- func shouldCompile (dotfile * resolver.Dotfile , config config.SourceConfig ) bool {
14- return len (dotfile .Sources ) > 1
13+ type dotfileCompiler struct {
14+ dotfile * resolver.Dotfile
15+ content * bytes.Buffer
16+ compiled bool
17+ config config.SourceConfig
18+ files []* os.File
19+ }
20+
21+ // ensureCompiled transforms the source dotfiles into the dotfile output. It
22+ // will not recompile if the dotfile has already been compiled.
23+ func (c * dotfileCompiler ) ensureCompiled () error {
24+ if c .compiled {
25+ return nil
26+ }
27+
28+ compiledData := []byte {}
29+
30+ for i , sourceFile := range c .files {
31+ data , err := ioutil .ReadAll (sourceFile )
32+ if err != nil {
33+ return err
34+ }
35+
36+ // 1. Always trim whitespace off of the source file.
37+ data = trimWhitespace (data )
38+
39+ // 2. For any source file that procedes after the first, trim shebang
40+ // markers for cleanlyness of bash configurations. We trim whitespace
41+ // again to remove any space after the shebang.
42+ if i != 0 {
43+ data = trimShebang (data )
44+ data = trimWhitespace (data )
45+ }
46+
47+ // Combine files with *one* blank line between them
48+ if i != 0 {
49+ compiledData = append (compiledData , '\n' , '\n' )
50+ }
51+
52+ compiledData = append (compiledData , data ... )
53+ }
54+
55+ // 3. Expand environment variables if the dotfile was marked.
56+ if c .dotfile .ExpandEnv {
57+ compiledData = expandEnvironment (compiledData )
58+ }
59+
60+ // 4. All files should end with a single newline
61+ compiledData = append (compiledData , '\n' )
62+
63+ // Store the compiled dotfile
64+ c .compiled = true
65+ c .content .Reset ()
66+ c .content .Write (compiledData )
67+
68+ return nil
69+ }
70+
71+ // Read implements the io.Reader interface. Calling read will compile the
72+ // dotfile into it's final byte slice.
73+ func (c * dotfileCompiler ) Read (p []byte ) (int , error ) {
74+ c .ensureCompiled ()
75+ return c .content .Read (p )
76+ }
77+
78+ // Close implments the io.Closer interface. Calling close will close all source
79+ // files associated to the dotfile.
80+ func (c * dotfileCompiler ) Close () error {
81+ var err error
82+
83+ for _ , file := range c .files {
84+ closeErr := file .Close ()
85+ if closeErr != nil {
86+ err = closeErr
87+ }
88+ }
89+
90+ return err
1591}
1692
1793// OpenDotfile opens a source dotfile for streaming compilation.
@@ -29,41 +105,24 @@ func OpenDotfile(dotfile *resolver.Dotfile, config config.SourceConfig) (io.Read
29105
30106 compiler := & dotfileCompiler {
31107 dotfile : dotfile ,
108+ content : bytes .NewBuffer (nil ),
32109 config : config ,
33110 files : files ,
34111 }
35112
36113 return compiler , nil
37114}
38115
39- type dotfileCompiler struct {
40- dotfile * resolver.Dotfile
41- config config.SourceConfig
42- files []* os.File
43- }
44-
45- // TODO: If we want we can make this thing do caching of compiled dotfiels if
46- // we expect to install them later
47- func (c * dotfileCompiler ) Read (p []byte ) (n int , err error ) {
48- readers := []io.Reader {}
49-
50- for _ , file := range c .files {
51- readers = append (readers , file )
116+ // mustCompile indicates if a dotfile must be compiled, or if a single-source
117+ // dotfile does not require any transformations and may be directly installed.
118+ func shouldCompile (dotfile * resolver.Dotfile , config config.SourceConfig ) bool {
119+ if len (dotfile .Sources ) > 1 {
120+ return true
52121 }
53122
54- // TODO: Implement filtered reading
55- return io .MultiReader (readers ... ).Read (p )
56- }
57-
58- func (c * dotfileCompiler ) Close () error {
59- var err error
60-
61- for _ , file := range c .files {
62- closeErr := file .Close ()
63- if closeErr != nil {
64- err = closeErr
65- }
123+ if dotfile .ExpandEnv {
124+ return true
66125 }
67126
68- return err
127+ return false
69128}
0 commit comments