web frontend for git (tangled's grandpa)
7
fork

Configure Feed

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

git: Add function to generate tar file from repo

authored by

Gabriel A. Giovanini and committed by
Anirudh Oppiliappan
86b2bf47 7e3307ef

+136
+136
git/git.go
··· 1 1 package git 2 2 3 3 import ( 4 + "archive/tar" 4 5 "fmt" 6 + "io" 7 + "io/fs" 8 + "path" 5 9 "sort" 10 + "time" 6 11 7 12 "github.com/go-git/go-git/v5" 8 13 "github.com/go-git/go-git/v5/plumbing" ··· 15 20 } 16 21 17 22 type TagList []*object.Tag 23 + 24 + // infoWrapper wraps the property of a TreeEntry so it can export fs.FileInfo 25 + // to tar WriteHeader 26 + type infoWrapper struct { 27 + name string 28 + size int64 29 + mode fs.FileMode 30 + modTime time.Time 31 + isDir bool 32 + } 18 33 19 34 func (self TagList) Len() int { 20 35 return len(self) ··· 154 169 } 155 170 return "", fmt.Errorf("unable to find main branch") 156 171 } 172 + 173 + // WriteTar writes itself from a tree into a binary tar file format. 174 + // prefix is root folder to be appended. 175 + func (g *GitRepo) WriteTar(w io.Writer, prefix string) error { 176 + tw := tar.NewWriter(w) 177 + defer tw.Close() 178 + 179 + c, err := g.r.CommitObject(g.h) 180 + if err != nil { 181 + return fmt.Errorf("commit object: %w", err) 182 + } 183 + 184 + tree, err := c.Tree() 185 + if err != nil { 186 + return err 187 + } 188 + 189 + walker := object.NewTreeWalker(tree, true, nil) 190 + defer walker.Close() 191 + 192 + name, entry, err := walker.Next() 193 + for ; err == nil; name, entry, err = walker.Next() { 194 + info, err := newInfoWrapper(name, prefix, &entry, tree) 195 + if err != nil { 196 + return err 197 + } 198 + 199 + header, err := tar.FileInfoHeader(info, "") 200 + if err != nil { 201 + return err 202 + } 203 + 204 + err = tw.WriteHeader(header) 205 + if err != nil { 206 + return err 207 + } 208 + 209 + if !info.IsDir() { 210 + file, err := tree.File(name) 211 + if err != nil { 212 + return err 213 + } 214 + 215 + reader, err := file.Blob.Reader() 216 + if err != nil { 217 + return err 218 + } 219 + 220 + _, err = io.Copy(tw, reader) 221 + if err != nil { 222 + reader.Close() 223 + return err 224 + } 225 + reader.Close() 226 + } 227 + } 228 + 229 + return nil 230 + } 231 + 232 + func newInfoWrapper( 233 + name string, 234 + prefix string, 235 + entry *object.TreeEntry, 236 + tree *object.Tree, 237 + ) (*infoWrapper, error) { 238 + var ( 239 + size int64 240 + mode fs.FileMode 241 + isDir bool 242 + ) 243 + 244 + if entry.Mode.IsFile() { 245 + file, err := tree.TreeEntryFile(entry) 246 + if err != nil { 247 + return nil, err 248 + } 249 + mode = fs.FileMode(file.Mode) 250 + 251 + size, err = tree.Size(name) 252 + if err != nil { 253 + return nil, err 254 + } 255 + } else { 256 + isDir = true 257 + mode = fs.ModeDir | fs.ModePerm 258 + } 259 + 260 + fullname := path.Join(prefix, name) 261 + return &infoWrapper{ 262 + name: fullname, 263 + size: size, 264 + mode: mode, 265 + modTime: time.Unix(0, 0), 266 + isDir: isDir, 267 + }, nil 268 + } 269 + 270 + func (i *infoWrapper) Name() string { 271 + return i.name 272 + } 273 + 274 + func (i *infoWrapper) Size() int64 { 275 + return i.size 276 + } 277 + 278 + func (i *infoWrapper) Mode() fs.FileMode { 279 + return i.mode 280 + } 281 + 282 + func (i *infoWrapper) ModTime() time.Time { 283 + return i.modTime 284 + } 285 + 286 + func (i *infoWrapper) IsDir() bool { 287 + return i.isDir 288 + } 289 + 290 + func (i *infoWrapper) Sys() any { 291 + return nil 292 + }