Artifact b2dcecb8c8fd972aaa4126fd95ccf3a6569438ce8c06dc33a10cafdb8c69c714:
- File
internal/checkout/manage.go
— part of check-in
[857b86be94]
at
2026-10-18 18:46:08
on branch feat/submanifest-reader
— refactor(checkout): keep the functions the cone touched within 70 lines
The unchanged-file pass of a commit, the on-disk half of a rename, the tracked-row lookup of Manage and Create's local records become helpers; Update's content precheck moves into buildUpdateMaps. The fossil interop test isolates fossil's home itself. (user: [email protected], size: 5379) [annotate] [blame] [check-ins using] [more...]
package checkout import ( "database/sql" "fmt" libfossil "github.com/danmestas/go-libfossil/internal/fsltype" ) // Manage adds files to tracking. For each path: // - Checks if already in vfile (skips if present) // - Reads file content from Storage // - Computes hash // - Inserts into vfile with rid=0, chnged=1 (marks as newly added) // // Panics if c is nil (TigerStyle precondition). func (c *Checkout) Manage(opts ManageOpts) (*ManageCounts, error) { if c == nil { panic("checkout.Manage: nil *Checkout") } counts := &ManageCounts{} vid, _, err := c.Version() if err != nil { return nil, fmt.Errorf("checkout.Manage: %w", err) } if err := c.refuseUncovered("Manage", opts.Paths...); err != nil { return counts, err } for _, path := range opts.Paths { tracked, err := c.isTracked(vid, path) if err != nil { return counts, err } if tracked { // Already tracked counts.Skipped++ if opts.Callback != nil { if err := opts.Callback(path, false); err != nil { return counts, fmt.Errorf("checkout.Manage: callback for %s: %w", path, err) } } continue } // Read file from Storage fullPath, err := c.safePath(path) if err != nil { return counts, fmt.Errorf("checkout.Manage: path traversal in %s: %w", path, err) } // Stat the on-disk file to capture its executable bit at add time. info, err := c.env.Storage.Stat(fullPath) if err != nil { return counts, fmt.Errorf("checkout.Manage: stat %s: %w", path, err) } isexe := 0 if modeIsExecutable(info.Mode()) { isexe = 1 } // Insert with rid=0 (newly added), chnged=1 (modified). islink is // written explicitly because a checkout made by fossil declares it // with no default. mhash stays NULL as fossil leaves it: it is only // meaningful during a merge. _, err = c.db.Exec( "INSERT INTO vfile(vid, pathname, rid, mrid, isexe, islink, chnged) "+ "VALUES(?, ?, 0, 0, ?, 0, 1)", int64(vid), path, isexe, ) if err != nil { return counts, fmt.Errorf("checkout.Manage: insert vfile: %w", err) } counts.Added++ if opts.Callback != nil { if err := opts.Callback(path, true); err != nil { return counts, fmt.Errorf("checkout.Manage: callback for %s: %w", path, err) } } } return counts, nil } // isTracked reports whether version vid's record has a row for path. func (c *Checkout) isTracked(vid libfossil.FslID, path string) (bool, error) { var id int64 err := c.db.QueryRow( "SELECT id FROM vfile WHERE vid=? AND pathname=?", int64(vid), path, ).Scan(&id) if err == sql.ErrNoRows { return false, nil } if err != nil { return false, fmt.Errorf("checkout.Manage: query vfile: %w", err) } return true, nil } // Unmanage removes files from tracking. For each path: // - If rid=0 (newly added, never committed): DELETE from vfile // - If rid>0 (existing tracked file): UPDATE vfile SET deleted=1 // // Panics if c is nil (TigerStyle precondition). func (c *Checkout) Unmanage(opts UnmanageOpts) error { if c == nil { panic("checkout.Unmanage: nil *Checkout") } vid, _, err := c.Version() if err != nil { return fmt.Errorf("checkout.Unmanage: %w", err) } // Handle VFileIDs if provided if len(opts.VFileIDs) > 0 { for _, vfileID := range opts.VFileIDs { var rid int64 var pathname string err := c.db.QueryRow( "SELECT rid, pathname FROM vfile WHERE id=?", int64(vfileID), ).Scan(&rid, &pathname) if err == sql.ErrNoRows { continue // ID not found, skip } if err != nil { return fmt.Errorf("checkout.Unmanage: query vfile id=%d: %w", vfileID, err) } if err := c.refuseUncovered("Unmanage", pathname); err != nil { return err } if err := c.unmanageFile(vfileID, rid, pathname, opts.Callback); err != nil { return fmt.Errorf("checkout.Unmanage: %w", err) } } return nil } // Handle Paths if err := c.refuseUncovered("Unmanage", opts.Paths...); err != nil { return err } for _, path := range opts.Paths { var vfileID libfossil.FslID var rid int64 err := c.db.QueryRow( "SELECT id, rid FROM vfile WHERE vid=? AND pathname=?", int64(vid), path, ).Scan(&vfileID, &rid) if err == sql.ErrNoRows { // Not tracked, skip silently continue } if err != nil { return fmt.Errorf("checkout.Unmanage: query vfile: %w", err) } if err := c.unmanageFile(vfileID, rid, path, opts.Callback); err != nil { return fmt.Errorf("checkout.Unmanage: %w", err) } } return nil } // unmanageFile handles the logic for a single file: // - rid=0: DELETE (newly added, never committed) // - rid>0: UPDATE deleted=1 (existing file from repo) func (c *Checkout) unmanageFile( vfileID libfossil.FslID, rid int64, pathname string, callback func(string) error, ) error { if rid == 0 { // Newly added, never committed — remove completely _, err := c.db.Exec("DELETE FROM vfile WHERE id=?", int64(vfileID)) if err != nil { return fmt.Errorf("checkout.Unmanage: delete vfile: %w", err) } } else { // Existing tracked file — mark as deleted _, err := c.db.Exec("UPDATE vfile SET deleted=1 WHERE id=?", int64(vfileID)) if err != nil { return fmt.Errorf("checkout.Unmanage: update vfile: %w", err) } } if callback != nil { if err := callback(pathname); err != nil { return fmt.Errorf("checkout.Unmanage: callback for %s: %w", pathname, err) } } return nil }