Files
mixer-tools/builder/format.go
T
Ashlesha Atrey f6dcd44f21 Implement logging for mixer
Implement the logging package for mixer.

A common log file can be set for all the mixer commands in the
builder.conf. E.g. `mixer config set Mixer.LOG <filepath>`

The log file and level can also be set for individual mixer
commands using the `--log` and `--log-level` flags respectively.

The various log levels are:
ERROR (1), WARNING (2), INFO (3), DEBUG (4) and VERBOSE (5).
Default log level is 4.

Fixes #666

Signed-off-by: Ashlesha Atrey ashlesha.atrey@intel.com
2020-04-30 13:57:58 -07:00

246 lines
7.6 KiB
Go

// Copyright © 2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package builder
import (
"github.com/clearlinux/mixer-tools/log"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/clearlinux/mixer-tools/helpers"
"github.com/pkg/errors"
)
// UpdateFormatVersion updates the builder.conf file with a new format version
func (b *Builder) UpdateFormatVersion(version string) error {
b.State.Mix.Format = version
return b.State.Save()
}
// CopyFullGroupsINI copies the initial ini file which has ALL bundle definitions
func (b *Builder) CopyFullGroupsINI() error {
return helpers.CopyFile(filepath.Join(b.Config.Builder.ServerStateDir, "full_groups.ini"), filepath.Join(b.Config.Builder.ServerStateDir, "groups.ini"))
}
// RevertFullGroupsINI copies back the full ini to the manifest creator accounts for deleted bundles
func (b *Builder) RevertFullGroupsINI() error {
return helpers.CopyFile(filepath.Join(b.Config.Builder.ServerStateDir, "groups.ini"), filepath.Join(b.Config.Builder.ServerStateDir, "full_groups.ini"))
}
// GetLastBuildVersion returns the version number of the most recent build
func (b *Builder) GetLastBuildVersion() (string, error) {
var lastVer []byte
var err error
filename := filepath.Join(b.Config.Builder.ServerStateDir, "image/LAST_VER")
if lastVer, err = ioutil.ReadFile(filename); os.IsNotExist(err) {
return "", err
}
return strings.TrimSpace(string(lastVer)), nil
}
func (b *Builder) getLastBuildUpstreamVersion() (string, error) {
lastMix, err := b.GetLastBuildVersion()
if err != nil {
return "", err
}
var lastVer []byte
filename := filepath.Join(b.Config.Builder.ServerStateDir, "www", lastMix, "upstreamver")
if lastVer, err = ioutil.ReadFile(filename); err != nil {
return "", err
}
return strings.TrimSpace(string(lastVer)), nil
}
// getFormatForVersion returns the format for the provided local version
func (b *Builder) getFormatForVersion(version string) (string, error) {
var format []byte
var err error
filename := filepath.Join(b.Config.Builder.ServerStateDir, "www", version, "format")
if format, err = ioutil.ReadFile(filename); err != nil {
return "", err
}
return strings.TrimSpace(string(format)), nil
}
// getLatestForFormat returns the latest local version for the provided format
func (b *Builder) getLatestForFormat(format string) (string, error) {
var lastVer []byte
var err error
filename := filepath.Join(b.Config.Builder.ServerStateDir, "www/version", "format"+format, "latest")
if lastVer, err = ioutil.ReadFile(filename); err != nil {
return "", err
}
return strings.TrimSpace(string(lastVer)), nil
}
func (b *Builder) getLocalUpstreamVersion(version string) (string, error) {
var localUpstreamVer []byte
var err error
filename := filepath.Join(b.Config.Builder.ServerStateDir, "www", version, "upstreamver")
if localUpstreamVer, err = ioutil.ReadFile(filename); err != nil {
return "", err
}
return strings.TrimSpace(string(localUpstreamVer)), nil
}
// StageMixForBump prepares the mix for the two format bumps required to pass an
// upstream format boundary. The current upstreamversion is saved in a temporary
// ".bump" file, and replaced with the latest version in the format range of the
// most recent build. This process is undone via UnstageMixFromBump.
func (b *Builder) stageMixForBump() error {
vBFile := filepath.Join(b.Config.Builder.VersionPath, b.UpstreamVerFile+".bump")
// bump file already exists; return early
if _, err := os.Stat(vBFile); !os.IsNotExist(err) {
return nil
}
version, err := b.getLastBuildUpstreamVersion()
if err != nil {
return err
}
_, _, latest, err := b.getUpstreamFormatRange(version)
if err != nil {
return err
}
latest += 10
// Copy current upstreamversion to upstreamversion.bump
vFile := filepath.Join(b.Config.Builder.VersionPath, b.UpstreamVerFile)
if err := helpers.CopyFile(vBFile, vFile); err != nil {
return err
}
// Set current upstreamversion to latest
err = ioutil.WriteFile(vFile, []byte(strconv.FormatUint(uint64(latest), 10)), 0644)
if err != nil {
return err
}
// Load updated upstreamversion
if err = b.ReadVersions(); err != nil {
return err
}
return b.getUpstreamBundles()
}
// UnstageMixFromBump resets the upstreamversion file from the temporary ".bump"
// file, if it exists. This returns the user to their desired upstream version
// after having completed the upstream format boundary bump builds.
func (b *Builder) UnstageMixFromBump() error {
vFile := filepath.Join(b.Config.Builder.VersionPath, b.UpstreamVerFile)
vBFile := filepath.Join(b.Config.Builder.VersionPath, b.UpstreamVerFile+".bump")
// No bump file; return early
if _, err := os.Stat(vBFile); os.IsNotExist(err) {
return nil
}
// Copy upstreamversion.bump to upstreamversion
if err := helpers.CopyFile(vFile, vBFile); err != nil {
return err
}
// Load updated upstreamversion
if err := b.ReadVersions(); err != nil {
return err
}
if err := b.getUpstreamBundles(); err != nil {
return err
}
return os.Remove(vBFile)
}
// CheckBumpNeeded returns nil if it successfully deduces there is no format
// bump boundary being crossed.
func (b *Builder) CheckBumpNeeded(silent bool) (bool, error) {
// Skip bump checks in offline mode
if Offline {
return false, nil
}
version, err := b.getLastBuildUpstreamVersion()
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
// Check what format our last built version is part of
oldVer, err := b.getUpstreamFormat(version)
if err != nil {
return false, err
}
// Check what format our to-be-built version is part of
newVer, err := b.getUpstreamFormat(b.UpstreamVer)
if err != nil {
return false, err
}
// Check both formats are real numbers
oldFmt, err := strconv.ParseUint(string(oldVer), 10, 32)
if err != nil {
return false, errors.New("Old format is not a number")
}
newFmt, err := strconv.ParseUint(string(newVer), 10, 32)
if err != nil {
return false, errors.New("Old format is not a number")
}
// We always need to perform a format bump if these are not equal
if oldFmt != newFmt {
// Stage the upstreamversion file for bump
if err = b.stageMixForBump(); err != nil {
return false, errors.Wrap(err, "Failed to stage mix for format bump")
}
format, first, latest, err := b.getUpstreamFormatRange(version)
if err != nil {
return false, err
}
// Don't print this if we have to loop a bunch of times to catch up on formats
if !silent {
log.Info(log.Mixer, "The upstream version for this build (%s) is outside the format range of your last mix "+
"(format %s, upstream versions %d to %d). This build cannot be done until you complete an "+
"upstream format build. Please run the following command to complete the format bump:\nmixer "+
"build upstream-format\nOnce this has completed you can re-run this build you are attempting to create.\n"+
"* Please note that if you are multiple format bumps behind, mixer will detect you are still behind and "+
"re-run the command until the proper format is reached.",
b.UpstreamVer, format, first, latest)
}
return true, nil
}
return false, nil
}