Skip to content

Conversation

@ttaylorr
Copy link
Contributor

This pull request removes the use of the *progress.Spinner type in git-lfs-prune(1) in favor of a more consistent logging scheme.

Before:

~/example (master) $ git lfs prune
Pruning 1 files, (18 B)tained
✔ 3 local objects, 2 retained, done
✔ Deleted 1 files, done

After:

~/example (master) $ git lfs prune
prune: 3 local object(s), 2 retained, done
prune: Deleting objects: 100% (1/1), done

This removes one of two existing uses of the *progress.Spinner implementation, and the next pull-request in this series will remove the other use-case, which will allow *progress.Spinner to be deleted.

Please let me know if you have any thoughts on the formatting of these messages. I tried to make them as similar as I would imagine Git writing them, with these thoughts in mind:

  1. Lowercase prefix of the command that is being run.
  2. ", done\n" on the end (courtesy of *tasklog.Logger).
  3. Use percentages where appropriate, text where otherwise.

/cc @git-lfs/core

@ttaylorr ttaylorr added this to the v2.4.0 milestone Nov 28, 2017
@ttaylorr
Copy link
Contributor Author

ttaylorr commented Nov 29, 2017

TODO: looks like there are some tests failing here that I have to look into.

@ttaylorr
Copy link
Contributor Author

ttaylorr commented Dec 2, 2017

All fixed. Here's a quick breakdown of what was going wrong --

  1. The final update sent from *SimpleTasks were sometimes being dropped since close()-ing the updates channel does not wait for acknowledgement from the tasklog.Logger. By adding a "secret" OnComplete() method that is called if the Task implements it, we can wait for the logger to close.

  2. Some of the final updates were being dropped in a race-y fashion because we were failing to call logger.Close() (fixed in 4b33121). Adding this call waits until not only all active tasks have closed, but also until the logger has logged all messages.

Copy link
Contributor

@technoweenie technoweenie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great start. I made some suggestions relating to where the tasks are initialized and cleaned up.

pruneDeleteFiles(prunableObjects, percentage)
}

logger.Close()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be moved to a defer right after the logger is initialized? That ensures that it's closed if this func returns early, such as when prunableObjects is empty.

}

func pruneTaskDisplayProgress(progressChan PruneProgressChan, waitg *sync.WaitGroup, spinner *progress.Spinner) {
func pruneTaskDisplayProgress(progressChan PruneProgressChan, waitg *sync.WaitGroup, task *tasklog.SimpleTask) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not crazy about this function receiving a task, and then closing it. What do you think about sending it the logger instead, so that the task is created, enqueued, used, and completed all in this func?

logger.Enqueue(spinner)
// enqueue a _new_ percentage task to track deletion progress.
percentage := tasklog.NewPercentageTask("prune: Deleting objects", uint64(len(prunableObjects)))
logger.Enqueue(percentage)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this percentage is only used inside pruneDeleteFiles(), why not pass logger to it instead. Same justification as my note on pruneTaskDisplayProgress().

}

func TestPercentageTaskCallsDoneWhenComplete(t *testing.T) {
t.Skip()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this skip temporary, or should the test be removed?

@ttaylorr
Copy link
Contributor Author

ttaylorr commented Dec 4, 2017

@technoweenie thanks for the feedback, I agree with everything you said 😄. I un-skipped the test in 088b2ab, and changed the above methods to take a *tasklog.Logger, not a tasklog.Task in cde392b.

Can you take another look? 🙇

func pruneDeleteFiles(prunableObjects []string, task *tasklog.PercentageTask) {
func pruneDeleteFiles(prunableObjects []string, logger *tasklog.Logger) {
task := tasklog.NewPercentageTask("prune: Deleting objects", uint64(len(prunableObjects)))
logger.Enqueue(task)
Copy link
Contributor

@technoweenie technoweenie Dec 4, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small idea for another PR:

task := logger.NewPercentageTask(...) // create and enqueue task
defer task.Complete()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️ I'm silly -- this exists! Changed in 65b4f34.

info.Logf("prune: %d file(s) would be pruned (%s)", len(prunableObjects), humanize.FormatBytes(uint64(totalSize)))
if verbose {
Print(verboseOutput.String())
for _, item := range verboseOutput {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can take out the two extra if verbose (here and L194), since verboseOutput will be empty in that case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good, call -- I changed this in 782c58c.

info.Logf("\n%s", item)
}
}
info.Complete()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be moved to a defer, allowing the one on L192 to be removed too. I point it out because I think having a consistent pattern for dealing with loggers and tasks is important. I really like how the tasklog package is shaping up :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I don't think that these calls to Complete() can be deferred, since pruneDeleteFiles creates a new task, which (for the *tasklog.Logger to output), requires there to be no actively running task.

Copy link
Contributor

@technoweenie technoweenie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few nitpicky things, but overall I think this is a nice improvement. The old prune output was fine, but I very much prefer the Git style output for some reason.

@ttaylorr ttaylorr merged commit a98f6a9 into master Dec 5, 2017
@ttaylorr ttaylorr deleted the prune-unify-formatting branch December 5, 2017 01:29
chrisd8088 added a commit to chrisd8088/git-lfs that referenced this pull request Feb 25, 2025
In PR git-lfs#2757 the output of the "git lfs prune" command was revised to
use the methods of the Logger structure of the "tasklog" package to
output progress messages, replacing use of the Spinner structure from
the older "progress" package.  The Spinner structure and its methods
were then removed in PR git-lfs#2759, and the "progress" package was removed
entirely in PR git-lfs#2762.

As part of this change, the "git lfs prune" command's progress messages
were reformatted so as to always begin with the Git LFS subcommand name,
for example, "prune: 8 local objects, 9 retained, done."

Two other Git LFS commands follow the same design, the "git lfs fetch"
and "git lfs migrate" commands, but no others.  Git commands also do
not prefix their progress messages with the name of the subcommand
(although messages from a Git remote may be reported with the prefix
"remote:").

To help bring all our commands' progress messages into alignment, we
simply remove the "prune:" prefix from the messages output by the
"git lfs prune" command.  We expect to revise the progress messages
from the "git lfs fetch" and "git lfs migrate" commands in the same
way in subsequent commits of this PR.
chrisd8088 added a commit to chrisd8088/git-lfs that referenced this pull request Feb 25, 2025
In PR git-lfs#2757 the output of the "git lfs prune" command was revised to
use the methods of the Logger structure of the "tasklog" package to
output progress messages, replacing use of the Spinner structure from
the older "progress" package.  The Spinner structure and its methods
were then removed in PR git-lfs#2759, and the "progress" package was removed
entirely in PR git-lfs#2762.

As part of this change, the "git lfs prune" command's progress messages
were reformatted so as to always begin with the Git LFS subcommand name,
for example, "prune: 8 local objects, 9 retained, done."

Two other Git LFS commands follow the same design, the "git lfs fetch"
and "git lfs migrate" commands, but no others.  Git commands also do
not prefix their progress messages with the name of the subcommand
(although messages from a Git remote may be reported with the prefix
"remote:").

To help bring all our commands' progress messages into alignment, we
simply remove the "prune:" prefix from the messages output by the
"git lfs prune" command.  We expect to revise the progress messages
from the "git lfs fetch" and "git lfs migrate" commands in the same
way in subsequent commits of this PR.
chrisd8088 added a commit to chrisd8088/git-lfs that referenced this pull request Feb 25, 2025
In PR git-lfs#2757 the output of the "git lfs prune" command was revised to
use the methods of the Logger structure of the "tasklog" package to
output progress messages, replacing use of the Spinner structure from
the older "progress" package.  The Spinner structure and its methods
were then removed in PR git-lfs#2759, and the "progress" package was removed
entirely in PR git-lfs#2762.

As part of this change, the "git lfs prune" command's progress messages
were reformatted so as to always begin with the Git LFS subcommand name,
for example, "prune: 8 local objects, 9 retained, done."

Two other Git LFS commands follow the same design, the "git lfs fetch"
and "git lfs migrate" commands, but no others.  Git commands also do
not prefix their progress messages with the name of the subcommand
(although messages from a Git remote may be reported with the prefix
"remote:").

To help bring all our commands' progress messages into alignment, we
simply remove the "prune:" prefix from the messages output by the
"git lfs prune" command.  We expect to revise the progress messages
from the "git lfs fetch" and "git lfs migrate" commands in the same
way in subsequent commits of this PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants