package receivepack import ( "context" "io" "codeberg.org/lindenii/furgit/format/pktline" common "codeberg.org/lindenii/furgit/protocol/v0v1/server" protoreceive "codeberg.org/lindenii/furgit/protocol/v0v1/server/receivepack" "codeberg.org/lindenii/furgit/receivepack/service" ) // TODO: Some more designing to do. In particular, we'd like to have access to // commit graphs and stored object abstractions and such here, especially because // hooks might want to access full repos, but we risk creating // circular dependencies if we import repository/ here. Might need an interface-ish // design, but that risks being over-complicated. // Theoretically we could also just give the hooks an os.Root but that // feels a bit ugly. // ReceivePack serves one receive-pack session over r/w. func ReceivePack( ctx context.Context, w pktline.WriteFlusher, r io.Reader, opts Options, ) error { err := validateOptions(opts) if err != nil { return err } version := parseVersion(opts.GitProtocol) base := common.NewSession(r, w, common.Options{ Version: version, Algorithm: opts.Algorithm, }) protoSession := protoreceive.NewSession(base, protoreceive.Capabilities{ ReportStatus: true, ReportStatusV2: true, DeleteRefs: true, SideBand64K: true, Quiet: true, Atomic: true, OfsDelta: true, PushOptions: true, ObjectFormat: opts.Algorithm, // TODO: PushCertNonce, SessionID, Agent, whatever. }) refs, err := advertisedRefs(opts) if err != nil { return err } err = protoSession.AdvertiseRefs(common.Advertisement{Refs: refs}) if err != nil { return err } req, err := protoSession.ReadRequest() if err != nil { return err } serviceReq := &service.Request{ Commands: translateCommands(req.Commands), PushOptions: append([]string(nil), req.PushOptions...), Atomic: req.Capabilities.Atomic, DeleteOnly: req.DeleteOnly, PackExpected: req.PackExpected, Pack: r, } svc := service.New(service.Options{ Algorithm: opts.Algorithm, Refs: opts.Refs, ExistingObjects: opts.ExistingObjects, ObjectsRoot: opts.ObjectsRoot, PromotedObjectPermissions: translatePromotedObjectPermissions( opts.PromotedObjectPermissions, ), Hook: translateHook(opts.Hook), HookIO: service.HookIO{ Progress: base.ProgressWriter(), Error: base.ErrorWriter(), }, }) result, err := svc.Execute(ctx, serviceReq) if err != nil { return err } protoResult := translateResult(result) if req.Capabilities.ReportStatusV2 { return protoSession.WriteReportStatusV2(protoResult) } if req.Capabilities.ReportStatus { return protoSession.WriteReportStatus(protoResult) } return nil }