Run starts copying given source objects to destination.
(ctx context.Context)
| 289 | |
| 290 | // Run starts copying given source objects to destination. |
| 291 | func (s Select) Run(ctx context.Context) error { |
| 292 | client, err := storage.NewRemoteClient(ctx, s.src, s.storageOpts) |
| 293 | if err != nil { |
| 294 | printError(s.fullCommand, s.op, err) |
| 295 | return err |
| 296 | } |
| 297 | |
| 298 | ctx, cancel := context.WithCancel(ctx) |
| 299 | defer cancel() |
| 300 | |
| 301 | objch, err := expandSource(ctx, client, false, s.src) |
| 302 | if err != nil { |
| 303 | printError(s.fullCommand, s.op, err) |
| 304 | return err |
| 305 | } |
| 306 | |
| 307 | var ( |
| 308 | merrorWaiter error |
| 309 | merrorObjects error |
| 310 | ) |
| 311 | |
| 312 | waiter := parallel.NewWaiter() |
| 313 | errDoneCh := make(chan struct{}) |
| 314 | writeDoneCh := make(chan struct{}) |
| 315 | resultCh := make(chan json.RawMessage, 128) |
| 316 | |
| 317 | go func() { |
| 318 | defer close(errDoneCh) |
| 319 | for err := range waiter.Err() { |
| 320 | printError(s.fullCommand, s.op, err) |
| 321 | merrorWaiter = multierror.Append(merrorWaiter, err) |
| 322 | } |
| 323 | }() |
| 324 | |
| 325 | go func() { |
| 326 | defer close(writeDoneCh) |
| 327 | var fatalError error |
| 328 | for { |
| 329 | record, ok := <-resultCh |
| 330 | if !ok { |
| 331 | break |
| 332 | } |
| 333 | if fatalError != nil { |
| 334 | // Drain the channel. |
| 335 | continue |
| 336 | } |
| 337 | if _, err := os.Stdout.Write(append(record, '\n')); err != nil { |
| 338 | // Stop reading upstream. Notably useful for EPIPE. |
| 339 | cancel() |
| 340 | printError(s.fullCommand, s.op, err) |
| 341 | fatalError = err |
| 342 | } |
| 343 | } |
| 344 | }() |
| 345 | |
| 346 | excludePatterns, err := createRegexFromWildcard(s.exclude) |
| 347 | if err != nil { |
| 348 | printError(s.fullCommand, s.op, err) |
no test coverage detected