github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/overlord/patch/patch2.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 patch
    21  
    22  import (
    23  	"github.com/snapcore/snapd/overlord/state"
    24  	"github.com/snapcore/snapd/snap"
    25  )
    26  
    27  func init() {
    28  	patches[2] = []PatchFunc{patch2}
    29  }
    30  
    31  type patch2SideInfo struct {
    32  	RealName          string        `yaml:"name,omitempty" json:"name,omitempty"`
    33  	SnapID            string        `yaml:"snap-id" json:"snap-id"`
    34  	Revision          snap.Revision `yaml:"revision" json:"revision"`
    35  	Channel           string        `yaml:"channel,omitempty" json:"channel,omitempty"`
    36  	DeveloperID       string        `yaml:"developer-id,omitempty" json:"developer-id,omitempty"`
    37  	Developer         string        `yaml:"developer,omitempty" json:"developer,omitempty"` // XXX: obsolete, will be retired after full backfilling of DeveloperID
    38  	EditedSummary     string        `yaml:"summary,omitempty" json:"summary,omitempty"`
    39  	EditedDescription string        `yaml:"description,omitempty" json:"description,omitempty"`
    40  	Size              int64         `yaml:"size,omitempty" json:"size,omitempty"`
    41  	Sha512            string        `yaml:"sha512,omitempty" json:"sha512,omitempty"`
    42  	Private           bool          `yaml:"private,omitempty" json:"private,omitempty"`
    43  }
    44  
    45  type patch2DownloadInfo struct {
    46  	AnonDownloadURL string `json:"anon-download-url,omitempty"`
    47  	DownloadURL     string `json:"download-url,omitempty"`
    48  }
    49  
    50  type patch2Flags int
    51  
    52  type patch2SnapState struct {
    53  	SnapType string            `json:"type"` // Use Type and SetType
    54  	Sequence []*patch2SideInfo `json:"sequence"`
    55  	Active   bool              `json:"active,omitempty"`
    56  	// Current indicates the current active revision if Active is
    57  	// true or the last active revision if Active is false
    58  	// (usually while a snap is being operated on or disabled)
    59  	Current snap.Revision `json:"current"`
    60  	Channel string        `json:"channel,omitempty"`
    61  	Flags   patch2Flags   `json:"flags,omitempty"`
    62  }
    63  
    64  type patch2SnapSetup struct {
    65  	// FIXME: rename to RequestedChannel to convey the meaning better
    66  	Channel string `json:"channel,omitempty"`
    67  	UserID  int    `json:"user-id,omitempty"`
    68  
    69  	Flags patch2Flags `json:"flags,omitempty"`
    70  
    71  	SnapPath string `json:"snap-path,omitempty"`
    72  
    73  	DownloadInfo *patch2DownloadInfo `json:"download-info,omitempty"`
    74  	SideInfo     *patch2SideInfo     `json:"side-info,omitempty"`
    75  }
    76  
    77  func patch2SideInfoFromPatch1(oldInfo *patch1SideInfo, name string) *patch2SideInfo {
    78  	return &patch2SideInfo{
    79  		RealName:          name, // NOTE: OfficialName dropped
    80  		SnapID:            oldInfo.SnapID,
    81  		Revision:          oldInfo.Revision,
    82  		Channel:           oldInfo.Channel,
    83  		Developer:         oldInfo.Developer, // NOTE: no DeveloperID in patch1SideInfo
    84  		EditedSummary:     oldInfo.EditedSummary,
    85  		EditedDescription: oldInfo.EditedDescription,
    86  		Size:              oldInfo.Size,
    87  		Sha512:            oldInfo.Sha512,
    88  		Private:           oldInfo.Private,
    89  	}
    90  }
    91  
    92  func patch2SequenceFromPatch1(oldSeq []*patch1SideInfo, name string) []*patch2SideInfo {
    93  	newSeq := make([]*patch2SideInfo, len(oldSeq))
    94  	for i, si := range oldSeq {
    95  		newSeq[i] = patch2SideInfoFromPatch1(si, name)
    96  	}
    97  
    98  	return newSeq
    99  }
   100  
   101  func patch2SnapStateFromPatch1(oldSnapState *patch1SnapState, name string) *patch2SnapState {
   102  	return &patch2SnapState{
   103  		SnapType: oldSnapState.SnapType,
   104  		Sequence: patch2SequenceFromPatch1(oldSnapState.Sequence, name),
   105  		Active:   oldSnapState.Active,
   106  		Current:  oldSnapState.Current,
   107  		Channel:  oldSnapState.Channel,
   108  		Flags:    patch2Flags(oldSnapState.Flags),
   109  	}
   110  }
   111  
   112  // patch2:
   113  // - migrates SnapSetup.Name to SnapSetup.SideInfo.RealName
   114  // - backfills SnapState.{Sequence,Candidate}.RealName if its missing
   115  func patch2(s *state.State) error {
   116  
   117  	var oldStateMap map[string]*patch1SnapState
   118  	err := s.Get("snaps", &oldStateMap)
   119  	if err == state.ErrNoState {
   120  		return nil
   121  	}
   122  	if err != nil {
   123  		return err
   124  	}
   125  	newStateMap := make(map[string]*patch2SnapState, len(oldStateMap))
   126  
   127  	for key, oldSnapState := range oldStateMap {
   128  		newStateMap[key] = patch2SnapStateFromPatch1(oldSnapState, key)
   129  	}
   130  
   131  	// migrate SnapSetup in all tasks:
   132  	//  - the new SnapSetup uses SideInfo, backfil from Candidate
   133  	//  - also move SnapSetup.{Name,Revision} into SnapSetup.SideInfo.{RealName,Revision}
   134  	var oldSS patch1SnapSetup
   135  	for _, t := range s.Tasks() {
   136  		var newSS patch2SnapSetup
   137  		err := t.Get("snap-setup", &oldSS)
   138  		if err == state.ErrNoState {
   139  			continue
   140  		}
   141  		if err != nil && err != state.ErrNoState {
   142  			return err
   143  		}
   144  		// some things stay the same
   145  		newSS.Channel = oldSS.Channel
   146  		newSS.Flags = patch2Flags(oldSS.Flags)
   147  		newSS.SnapPath = oldSS.SnapPath
   148  		// ... and some change
   149  		newSS.SideInfo = &patch2SideInfo{}
   150  		if snapst, ok := oldStateMap[oldSS.Name]; ok && snapst.Candidate != nil {
   151  			newSS.SideInfo = patch2SideInfoFromPatch1(snapst.Candidate, oldSS.Name)
   152  		}
   153  		if newSS.SideInfo.RealName == "" {
   154  			newSS.SideInfo.RealName = oldSS.Name
   155  		}
   156  		if newSS.SideInfo.Revision.Unset() {
   157  			newSS.SideInfo.Revision = oldSS.Revision
   158  		}
   159  		t.Set("snap-setup", &newSS)
   160  	}
   161  
   162  	s.Set("snaps", newStateMap)
   163  
   164  	return nil
   165  }