github.com/sirkon/goproxy@v1.4.8/plugin/vcs/module.go (about) 1 package vcs 2 3 import ( 4 "context" 5 "io" 6 "io/ioutil" 7 "os" 8 "time" 9 10 "github.com/rs/zerolog" 11 12 "github.com/sirkon/goproxy" 13 "github.com/sirkon/goproxy/internal/errors" 14 "github.com/sirkon/goproxy/internal/modfetch" 15 ) 16 17 type vcsModule struct { 18 repo modfetch.Repo 19 } 20 21 func (s *vcsModule) ModulePath() string { 22 return s.repo.ModulePath() 23 } 24 25 func (s *vcsModule) Versions(ctx context.Context, prefix string) (tags []string, err error) { 26 defer func() { 27 if err != nil { 28 err = errors.Wrap(err, "vcs getting versions") 29 } 30 }() 31 type data struct { 32 tags []string 33 err error 34 } 35 dataChan := make(chan data, 1) 36 go func() { 37 t, e := s.repo.Versions(prefix) 38 if len(t) == 0 { 39 info, err := s.repo.Latest() 40 if err != nil { 41 e = err 42 } else { 43 t = []string{info.Version} 44 } 45 } 46 dataChan <- data{ 47 tags: t, 48 err: e, 49 } 50 }() 51 52 select { 53 case info := <-dataChan: 54 return info.tags, info.err 55 case <-ctx.Done(): 56 return nil, ctx.Err() 57 } 58 } 59 60 func (s *vcsModule) Stat(ctx context.Context, rev string) (res *goproxy.RevInfo, err error) { 61 defer func() { 62 if err != nil { 63 err = errors.Wrap(err, "vcs getting stat") 64 } 65 }() 66 67 type data struct { 68 info *goproxy.RevInfo 69 err error 70 } 71 dataChan := make(chan data, 1) 72 go func() { 73 raw, err := s.repo.Stat(rev) 74 if err != nil { 75 dataChan <- data{ 76 info: nil, 77 err: err, 78 } 79 return 80 } 81 res := &goproxy.RevInfo{} 82 res.Name = raw.Name 83 res.Short = raw.Short 84 res.Time = raw.Time.Format(time.RFC3339) 85 res.Version = raw.Version 86 dataChan <- data{ 87 info: res, 88 err: nil, 89 } 90 }() 91 92 select { 93 case res := <-dataChan: 94 return res.info, res.err 95 case <-ctx.Done(): 96 return nil, ctx.Err() 97 } 98 } 99 100 func (s *vcsModule) GoMod(ctx context.Context, version string) (file []byte, err error) { 101 defer func() { 102 if err != nil { 103 err = errors.Wrap(err, "vcs getting go.mod") 104 } 105 }() 106 107 type data struct { 108 data []byte 109 err error 110 } 111 dataChan := make(chan data, 1) 112 go func() { 113 res, err := s.repo.GoMod(version) 114 dataChan <- data{ 115 data: res, 116 err: err, 117 } 118 }() 119 120 select { 121 case res := <-dataChan: 122 return res.data, res.err 123 case <-ctx.Done(): 124 return nil, ctx.Err() 125 } 126 } 127 128 func (s *vcsModule) Zip(ctx context.Context, version string) (file io.ReadCloser, err error) { 129 type data struct { 130 file io.ReadCloser 131 err error 132 } 133 dataChan := make(chan data, 1) 134 135 go func() { 136 dir, err := ioutil.TempDir(".", ".downloads") 137 if err != nil { 138 dataChan <- data{ 139 file: nil, 140 err: errors.Wrap(err, "vcs creating temporary directory to save source archive"), 141 } 142 } 143 defer func() { 144 if err := os.RemoveAll(dir); err != nil { 145 zerolog.Ctx(ctx).Error().Err(err).Msg("failed to remove temporary directory") 146 } 147 }() 148 fileName, err := s.repo.Zip(version, dir) 149 if err != nil { 150 dataChan <- data{ 151 file: nil, 152 err: errors.Wrap(err, "vcs getting source archive"), 153 } 154 return 155 } 156 157 osFile, err := os.Open(fileName) 158 if err != nil { 159 dataChan <- data{ 160 file: nil, 161 err: errors.Wrap(err, "vcs opening downloaded source archive"), 162 } 163 return 164 } 165 166 dataChan <- data{ 167 file: osFile, 168 err: nil, 169 } 170 }() 171 172 select { 173 case res := <-dataChan: 174 return res.file, res.err 175 case <-ctx.Done(): 176 return nil, errors.Wrap(ctx.Err(), "vcs getting source archive") 177 } 178 }