Merge branch 'main' into 19868-pca-in-ml
[lightning.git] / diff.go
1 // Copyright (C) The Lightning Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package lightning
6
7 import (
8         "bufio"
9         "bytes"
10         "flag"
11         "fmt"
12         "io"
13         "os"
14
15         "github.com/arvados/lightning/hgvs"
16 )
17
18 type diffFasta struct{}
19
20 func (cmd *diffFasta) RunCommand(prog string, args []string, stdin io.Reader, stdout, stderr io.Writer) int {
21         var err error
22         defer func() {
23                 if err != nil {
24                         fmt.Fprintf(stderr, "%s\n", err)
25                 }
26         }()
27         flags := flag.NewFlagSet("", flag.ContinueOnError)
28         flags.SetOutput(stderr)
29         offset := flags.Int("offset", 0, "coordinate offset")
30         sequence := flags.String("sequence", "chr1", "sequence label")
31         timeout := flags.Duration("timeout", 0, "timeout (examples: \"1s\", \"1ms\")")
32         err = flags.Parse(args)
33         if err == flag.ErrHelp {
34                 err = nil
35                 return 0
36         } else if err != nil {
37                 return 2
38         } else if len(flags.Args()) != 2 {
39                 err = fmt.Errorf("usage: %s [options] a.fasta b.fasta", prog)
40                 return 2
41         }
42
43         var fasta [2][]byte
44         errs := make(chan error, 2)
45         for idx, fnm := range flags.Args() {
46                 idx, fnm := idx, fnm
47                 go func() {
48                         f, err := os.Open(fnm)
49                         if err != nil {
50                                 errs <- err
51                                 return
52                         }
53                         defer f.Close()
54                         scanner := bufio.NewScanner(f)
55                         scanner.Buffer(nil, 64*1024*1024)
56                         for scanner.Scan() {
57                                 buf := scanner.Bytes()
58                                 if len(buf) > 0 && buf[0] != '>' {
59                                         fasta[idx] = append(fasta[idx], bytes.ToUpper(buf)...)
60                                 }
61                         }
62                         errs <- scanner.Err()
63                 }()
64         }
65         for range flags.Args() {
66                 if err = <-errs; err != nil {
67                         return 1
68                 }
69         }
70
71         variants, timedOut := hgvs.Diff(string(fasta[0]), string(fasta[1]), *timeout)
72         if *offset != 0 {
73                 for i := range variants {
74                         variants[i].Position += *offset
75                 }
76         }
77         for _, v := range variants {
78                 fmt.Fprintf(stdout, "%s:g.%s\t%s\t%d\t%s\t%s\t%v\n", *sequence, v.String(), *sequence, v.Position, v.Ref, v.New, timedOut)
79         }
80         return 0
81 }