Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Console] Advancing a progress bar clears too many lines #52446

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
danepowell opened this issue Nov 3, 2023 · 16 comments
Closed

[Console] Advancing a progress bar clears too many lines #52446

danepowell opened this issue Nov 3, 2023 · 16 comments

Comments

@danepowell
Copy link
Contributor

Symfony version(s) affected

6.3.4

Description

Our console application creates checklists based on Symfony progress bars to represent the progress of multi-step commands. You can see the code for this at https://github.com/acquia/cli/tree/main/src/Output

As of Symfony 6.3.4 (specifically #51378), these checklists / progress bars don't work correctly. Whenever the progress bar advances, it clears two lines instead of one, causing it to "eat" the prior console output, including the checklist. See a video of this in action with a few more details here: https://github.com/acquia/cli/issues/1620

This seems to be a regression introduced by #51378 . I'm not sure if it's a general regression or a problem with our particular implementation of progress bars.

How to reproduce

See https://github.com/acquia/cli/issues/1620

I haven't figured out how to reproduce this outside of our application yet

Possible Solution

No response

Additional Context

No response

@maxbeckers
Copy link
Contributor

@danepowell you are right.

The reason is the following line:

parent::doWrite($deleteLastLine ? $lastLine.$message : $message, true);

There is always used the newline parameter with true.
So the change is, when we have the following example (pseudo code):

$pgBar = new ProgressBar();
...
$pgBar->display();

Then is called the ConsoleSectionOutput::doWrite with the parameters "Your Text\n" and newline = false.

Before #51378 the parent::doWrite was called with "Your Text\n" and newline = true. This results in "Your Text\n\n" in the output.
Now because of the new logic it sets the message to "Your Text" and newline = true. Now the parent::doWrite is called with "Your Text" and newline = true. This results in "Your Text\n".

/cc @chalasr @nicolas-grekas this is the change of output what comes from #51378. But this was exactly the issue to fix this behavior of the duplicated "\n". This comes from a ProgressBar with the format "%bar% %message%\n%detail%" when then %detail% is set to an empty string. Could be fixed by setting detail to a whitespace or whatever to fix the problem, but yeah, it's a change of the behavior.

@danepowell
Copy link
Contributor Author

@joelwurtz would you mind taking a look at this since you authored #51378 ?

@danepowell
Copy link
Contributor Author

@chalasr @nicolas-grekas could you take a look at this regression? If it was an intended change of behavior, can you suggest how downstream projects like ACLI should adjust to fix it?

@chalasr
Copy link
Member

chalasr commented Dec 18, 2023

@danepowell Sorry for the lack of reply. We either need someone work on a fix or revert the bugfix that introduced this regression. I feel like it'd be worth trying to fix the regression without reverting the PR that introduced it, but I'm personally not able to take that time right now hence some help would be needed. Maybe something around:

Could be fixed by setting detail to a whitespace or whatever to fix the problem, but yeah, it's a change of the behavior.

would be enough if it doesn't cause more trouble.

@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

@danepowell
Copy link
Contributor Author

Still a bug

@carsonbot carsonbot removed the Stalled label Jun 19, 2024
@joelwurtz
Copy link
Contributor

I tried to resolve it but i'm struggling creating a reproducer based on your code, i didn't manage to do it, i'm certainly missing something from your code, ATM i wrote this :

<?php

require 'vendor/autoload.php';

$output = new \Symfony\Component\Console\Output\ConsoleOutput();
$input = new \Symfony\Component\Console\Input\ArgvInput();
$section = $output->section();

function run_step($section, $title)
{
    $progressBar = new \Symfony\Component\Console\Helper\ProgressBar($section);
    $progressBar->setBarCharacter('<info>✔</info>');
    $progressBar->setProgressCharacter('');
    $progressBar->setEmptyBarCharacter('');
    $progressBar->setFormat("    %bar% %message%\n      > %detail%");
    $progressBar->setBarWidth(1);
    $progressBar->setMessage($title);
    $progressBar->setMessage('run 1', 'detail');

    sleep(1);
    $progressBar->setMessage('run 2', 'detail');
    $progressBar->advance();

    sleep(1);
    $progressBar->setMessage('run 3', 'detail');
    $progressBar->advance();

    sleep(1);
    $progressBar->setMessage('run 4', 'detail');
    $progressBar->advance();

    sleep(1);
    $progressBar->setMessage('run 5', 'detail');
    $progressBar->advance();

    sleep(1);
    $progressBar->setMessage('run 6', 'detail');
    $progressBar->advance();

    sleep(1);
    $progressBar->finish();
    $section->clear(1);
}

$io = new \Symfony\Component\Console\Style\SymfonyStyle($input, $section);
$io->confirm('Do you want to continue?', true);

run_step($section, 'Step 1');
run_step($section, 'Step 2');
run_step($section, 'Step 3');
run_step($section, 'Step 4');

@stof
Copy link
Member

stof commented Jun 20, 2024

@joelwurtz the format you use is not the same than in #52446 (comment)

@joelwurtz
Copy link
Contributor

Wich format ? You mean about using the display method ? I try with that also and it's the same.

I'm not trying to reproduce this bug directly using console output, but more with progress bar and other method from section output as i think it may be more the way progress bar or other helper use the section rather than an implementation bug.

(I try to change directly the implementation but a lot of tests fails, and a lot of output is done unecesseraly)

@danepowell
Copy link
Contributor Author

danepowell commented Jul 10, 2024

I set the detail in the progressBar format to a whitespace and this seems to work around the new behavior: acquia/cli#1766

In my code, doWrite is called with ⌛ Removing temporary artifact directory...\n and newline false. In the original code, this is maintained when addContent is called, then a second newline gets added.

But after #51378, this is changed to ⌛ Removing temporary artifact directory... and newline true. Then only a single newline is added (it should be two newlines like before).

This seems like a bug; or there should be a better workaround than fudging a whitespace after the newline.

@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

@danepowell
Copy link
Contributor Author

Still relevant

@carsonbot carsonbot removed the Stalled label Jan 11, 2025
@cedric-anne
Copy link
Contributor

cedric-anne commented Feb 27, 2025

I confirm the issue persist. Here is a single command app to reproduce this issue.

#!/usr/bin/env php
<?php
require __DIR__.'/vendor/autoload.php';

use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\SingleCommandApplication;

(new SingleCommandApplication())
    ->setCode(function (InputInterface $input, OutputInterface $output): int {
        $progress_bar = new ProgressBar($output->section());
        $progress_bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '<comment>%message%</comment>' . PHP_EOL);
        $progress_bar->setMaxSteps(200);
        $progress_bar->setMessage('');
        $progress_bar->start();

        $result_section = $output->section();

        $progress_bar->setMessage('Doing something...');
        for ($i = 1; $i <= 100; $i++) {
            usleep(30_000);
            $progress_bar->advance();
        }
        $result_section->writeln('<info>Something has been done successfully.</info>');

        $progress_bar->setMessage('Doing something else...');
        for ($i = 1; $i <= 100; $i++) {
            usleep(30_000);
            $progress_bar->advance();
        }
        $result_section->writeln('<info>Something else has been done successfully.</info>');

        $progress_bar->setMessage('');
        $progress_bar->finish();

        return 1;
    })
    ->run();

The following capture shows this unexpected behaviour on gnome-term (the default ubuntu terminal).
Image

@joelwurtz
Copy link
Contributor

joelwurtz commented Feb 27, 2025

Thanks for the reproducer, i'm not sure where the bug should be fixed however

I managed to have something working by doing this :

#!/usr/bin/env php
<?php

require __DIR__.'/vendor/autoload.php';

use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\SingleCommandApplication;

(new SingleCommandApplication())
    ->setCode(function (InputInterface $input, OutputInterface $output): int {
        $progress_bar = new ProgressBar($output->section());
        $progress_bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '<comment>%message%</comment>');
        $progress_bar->setMaxSteps(200);
        $progress_bar->setMessage('Start');
        $progress_bar->start();

        $result_section = $output->section();

        $progress_bar->setMessage('Doing something...');
        for ($i = 1; $i <= 100; $i++) {
            usleep(30_000);
            $progress_bar->advance();
        }
        $result_section->writeln('<info>Something has been done successfully.</info>');

        $progress_bar->setMessage('Doing something else...');
        for ($i = 1; $i <= 100; $i++) {
            usleep(30_000);
            $progress_bar->advance();
        }
        $result_section->writeln('<info>Something else has been done successfully.</info>');

        $progress_bar->setMessage('');
        $progress_bar->finish();

        return 1;
    })
    ->run();
  • Removing the PHP_EOL at the end of the format (it's not needed)
  • Setting a starting text for the format

For me the bug may be in the message from progess bar passed to the section: it should remove PHP_EOL at the end of it

@cedric-anne
Copy link
Contributor

In fact, in my application, I have 2 PHP_EOL at the end of the progress bar format. I made it this way to have a "padding" between my progress bar and my result section.

Anyway, thanks for the workaround.

@joelwurtz
Copy link
Contributor

Made a fix in #59874

fabpot added a commit that referenced this issue Mar 3, 2025
…there is an EOL (joelwurtz)

This PR was merged into the 6.4 branch.

Discussion
----------

[Console] fix progress bar messing output in section when there is an EOL

| Q             | A
| ------------- | ---
| Branch?       | 6.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Issues        | #52446
| License       | MIT

This fix the progress bar making the output erase previous line when there is an EOL at the end of it

Commits
-------

cae2241 fix(console): fix progress bar messing output in section when there is an EOL
@fabpot fabpot closed this as completed Mar 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants