github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/overlord/snapstate/progress.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package snapstate
    21  
    22  import (
    23  	"math"
    24  
    25  	"github.com/snapcore/snapd/overlord/state"
    26  	"github.com/snapcore/snapd/progress"
    27  )
    28  
    29  // taskProgressAdapter adapts a task into a progress.Meter
    30  // until we have native install/update/remove.
    31  type taskProgressAdapter struct {
    32  	task     *state.Task
    33  	unlocked bool
    34  	label    string
    35  	total    float64
    36  	current  float64
    37  
    38  	lastReported float64
    39  }
    40  
    41  // NewTaskProgressAdapterUnlocked creates an adapter of the task into a progress.Meter to use while the state is unlocked
    42  func NewTaskProgressAdapterUnlocked(t *state.Task) progress.Meter {
    43  	return &taskProgressAdapter{task: t, unlocked: true}
    44  }
    45  
    46  // NewTaskProgressAdapterUnlocked creates an adapter of the task into a progress.Meter to use while the state is locked
    47  func NewTaskProgressAdapterLocked(t *state.Task) progress.Meter {
    48  	return &taskProgressAdapter{task: t, unlocked: false}
    49  }
    50  
    51  // Start sets total
    52  func (t *taskProgressAdapter) Start(label string, total float64) {
    53  	t.label = label
    54  	t.total = total
    55  	t.Set(0.0)
    56  }
    57  
    58  // Set sets the current progress
    59  func (t *taskProgressAdapter) Set(current float64) {
    60  	t.current = current
    61  
    62  	// check if we made at least "minProgress" before we lock the state
    63  	// (using Abs to ensure that even if lastReported is smaller than
    64  	//  current we still report progress)
    65  	const minProgress = 0.2 / 100.0
    66  	if current != 0.0 && math.Abs(t.current-t.lastReported)/t.total < minProgress {
    67  		return
    68  	}
    69  
    70  	t.lastReported = t.current
    71  	// set progress in task
    72  	if t.unlocked {
    73  		t.task.State().Lock()
    74  		defer t.task.State().Unlock()
    75  	}
    76  	t.task.SetProgress(t.label, int(current), int(t.total))
    77  }
    78  
    79  // SetTotal sets the maximum progress
    80  func (t *taskProgressAdapter) SetTotal(total float64) {
    81  	t.total = total
    82  }
    83  
    84  // Finished set the progress to 100%
    85  func (t *taskProgressAdapter) Finished() {
    86  	if t.unlocked {
    87  		t.task.State().Lock()
    88  		defer t.task.State().Unlock()
    89  	}
    90  	t.task.SetProgress(t.label, int(t.total), int(t.total))
    91  }
    92  
    93  // Write sets the current write progress
    94  func (t *taskProgressAdapter) Write(p []byte) (n int, err error) {
    95  	t.Set(t.current + float64(len(p)))
    96  	return len(p), nil
    97  }
    98  
    99  // Notify notifies
   100  func (t *taskProgressAdapter) Notify(msg string) {
   101  	if t.unlocked {
   102  		t.task.State().Lock()
   103  		defer t.task.State().Unlock()
   104  	}
   105  	t.task.Logf(msg)
   106  }
   107  
   108  // Spin does nothing
   109  func (t *taskProgressAdapter) Spin(msg string) {
   110  }