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 }