Monorepo for Tangled tangled.org
2

Configure Feed

Select the types of activity you want to include in your feed.

1package service 2 3import ( 4 "bytes" 5 "fmt" 6 "io" 7 "log" 8 "net/http" 9 "os/exec" 10 "strings" 11 "sync" 12 "syscall" 13 14 "tangled.org/core/knotserver/sandbox" 15) 16 17// Mostly from charmbracelet/soft-serve and sosedoff/gitkit. 18 19type ServiceCommand struct { 20 GitProtocol string 21 Dir string 22 Stdin io.Reader 23 Stdout http.ResponseWriter 24 Sandbox sandbox.Backend 25} 26 27func (c *ServiceCommand) RunService(cmd *exec.Cmd) error { 28 cmd.Env = append(cmd.Env, fmt.Sprintf("GIT_PROTOCOL=%s", c.GitProtocol)) 29 30 if c.Sandbox != nil { 31 var wrapErr error 32 cmd, wrapErr = c.Sandbox.Wrap(c.Dir, cmd) 33 if wrapErr != nil { 34 return fmt.Errorf("sandbox wrap: %w", wrapErr) 35 } 36 } else { 37 cmd.Dir = c.Dir 38 } 39 40 if cmd.SysProcAttr == nil { 41 cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} 42 } 43 44 var stderr bytes.Buffer 45 cmd.Stderr = &stderr 46 47 stdoutPipe, err := cmd.StdoutPipe() 48 if err != nil { 49 return fmt.Errorf("failed to create stdout pipe: %w", err) 50 } 51 52 stdinPipe, err := cmd.StdinPipe() 53 if err != nil { 54 return fmt.Errorf("failed to create stdin pipe: %w", err) 55 } 56 57 if err := cmd.Start(); err != nil { 58 return fmt.Errorf("failed to start '%s': %w", cmd.String(), err) 59 } 60 61 var wg sync.WaitGroup 62 63 if c.Stdin != nil { 64 wg.Add(1) 65 go func() { 66 defer wg.Done() 67 defer stdinPipe.Close() 68 io.Copy(stdinPipe, c.Stdin) 69 }() 70 } 71 72 if c.Stdout != nil { 73 wg.Add(1) 74 go func() { 75 defer wg.Done() 76 io.Copy(newWriteFlusher(c.Stdout), stdoutPipe) 77 stdoutPipe.Close() 78 }() 79 } 80 81 wg.Wait() 82 83 if err := cmd.Wait(); err != nil { 84 return fmt.Errorf("'%s' failed: %w, stderr: %s", cmd.String(), err, stderr.String()) 85 } 86 87 return nil 88} 89 90func (c *ServiceCommand) InfoRefs() error { 91 cmd := exec.Command("git", []string{ 92 "upload-pack", 93 "--stateless-rpc", 94 "--http-backend-info-refs", 95 ".", 96 }...) 97 98 if !strings.Contains(c.GitProtocol, "version=2") { 99 if err := packLine(c.Stdout, "# service=git-upload-pack\n"); err != nil { 100 log.Printf("git: failed to write pack line: %s", err) 101 return err 102 } 103 104 if err := packFlush(c.Stdout); err != nil { 105 log.Printf("git: failed to flush pack: %s", err) 106 return err 107 } 108 } 109 110 return c.RunService(cmd) 111} 112 113func (c *ServiceCommand) UploadArchive() error { 114 cmd := exec.Command("git", []string{ 115 "upload-archive", 116 ".", 117 }...) 118 119 return c.RunService(cmd) 120} 121 122func (c *ServiceCommand) UploadPack() error { 123 cmd := exec.Command("git", []string{ 124 "upload-pack", 125 "--stateless-rpc", 126 ".", 127 }...) 128 129 return c.RunService(cmd) 130} 131 132func packLine(w io.Writer, s string) error { 133 _, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s) 134 return err 135} 136 137func packFlush(w io.Writer) error { 138 _, err := fmt.Fprint(w, "0000") 139 return err 140}