<commit_before>package update

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"

	"github.com/experimental-platform/platconf/platconf"
)

// Opts contains command line parameters for the 'update' command
type Opts struct {
	Channel string `short:"c" long:"channel" description:"Channel to be installed"`
	Pullers int    `short:"p" long:"pullers" description:"Maximum images being pulled at once" default:"4"`
	//Force bool `short:"f" long:"force" description:"Force installing the current latest release"`
}

// Execute is the function ran when the 'update' command is used
func (o *Opts) Execute(args []string) error {
	os.Setenv("DOCKER_API_VERSION", "1.22")

	if o.Pullers < 1 {
		return errors.New("The maximum number of pullers must be > 0")
	}

	// TODO remove this later
	log.Fatal("The update functionality is not yet available.")

	err := runUpdate(o.Channel, "/", o.Pullers)
	if err != nil {
		button(buttonError)
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	return nil
}

func runUpdate(specifiedChannel string, rootDir string, maxPullers int) error {
	// prepare
	platconf.RequireRoot()
	button(buttonRainbow)
	setStatus("preparing", nil, nil)

	// get channel
	channel, channelSource := getChannel(specifiedChannel)
	logChannelDetection(channel, channelSource)

	// get release data
	releaseData, err := fetchReleaseData(channel)
	if err != nil {
		return err
	}

	// get & extract 'configure'
	configureImgData := releaseData.GetImageByName("quay.io/experimentalplatform/configure")
	if configureImgData == nil {
		return fmt.Errorf("configure image data not found in the manifest")
	}

	configureExtractDir, err := extractConfigure(configureImgData.Tag)
	if err != nil {
		return err
	}
	defer os.RemoveAll(configureExtractDir)

	// setup paths
	fmt.Println("Creating folders in '/etc/systemd' in case they don't exist yet.")
	err = setupPaths(rootDir)
	if err != nil {
		return err
	}

	// setup default hostname
	hostameFilePath := path.Join(rootDir, "/etc/protonet/hostname")
	if _, err = os.Stat(hostameFilePath); os.IsNotExist(err) {
		ioutil.WriteFile(hostameFilePath, []byte("protonet"), 0644)
	}

	err = performOSUpdate()
	if err != nil {
		// we also get an error on a "no update" result, so this is fine
		log.Println("update-engine returned error:", err.Error())
	}

	// TODO run configure
	err = setupUtilityScripts(rootDir, configureExtractDir)
	if err != nil {
		return err
	}

	// END TODO run configure
	err = pullAllImages(releaseData, maxPullers)
	if err != nil {
		return err
	}

	err = parseAllTemplates(rootDir, configureExtractDir, releaseData)
	if err != nil {
		return err
	}

	err = cleanupSystemd(rootDir)
	if err != nil {
		return err
	}

	setStatus("done", nil, nil)

	// TODO allow to skip the reboot
	exec.Command("/usr/sbin/shutdown", "--reboot", "1")

	return nil
}

func setupPaths(rootPrefix string) error {
	requiredPaths := []string{
		"/etc/protonet",<commit_msg>reboot properly<commit_after>package update

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path"

	"github.com/experimental-platform/platconf/platconf"
)

// Opts contains command line parameters for the 'update' command
type Opts struct {
	Channel string `short:"c" long:"channel" description:"Channel to be installed"`
	Pullers int    `short:"p" long:"pullers" description:"Maximum images being pulled at once" default:"4"`
	//Force bool `short:"f" long:"force" description:"Force installing the current latest release"`
}

// Execute is the function ran when the 'update' command is used
func (o *Opts) Execute(args []string) error {
	os.Setenv("DOCKER_API_VERSION", "1.22")

	if o.Pullers < 1 {
		return errors.New("The maximum number of pullers must be > 0")
	}

	// TODO remove this later
	log.Fatal("The update functionality is not yet available.")

	err := runUpdate(o.Channel, "/", o.Pullers)
	if err != nil {
		button(buttonError)
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	return nil
}

func runUpdate(specifiedChannel string, rootDir string, maxPullers int) error {
	// prepare
	platconf.RequireRoot()
	button(buttonRainbow)
	setStatus("preparing", nil, nil)

	// get channel
	channel, channelSource := getChannel(specifiedChannel)
	logChannelDetection(channel, channelSource)

	// get release data
	releaseData, err := fetchReleaseData(channel)
	if err != nil {
		return err
	}

	// get & extract 'configure'
	configureImgData := releaseData.GetImageByName("quay.io/experimentalplatform/configure")
	if configureImgData == nil {
		return fmt.Errorf("configure image data not found in the manifest")
	}

	configureExtractDir, err := extractConfigure(configureImgData.Tag)
	if err != nil {
		return err
	}
	defer os.RemoveAll(configureExtractDir)

	// setup paths
	fmt.Println("Creating folders in '/etc/systemd' in case they don't exist yet.")
	err = setupPaths(rootDir)
	if err != nil {
		return err
	}

	// setup default hostname
	hostameFilePath := path.Join(rootDir, "/etc/protonet/hostname")
	if _, err = os.Stat(hostameFilePath); os.IsNotExist(err) {
		ioutil.WriteFile(hostameFilePath, []byte("protonet"), 0644)
	}

	err = performOSUpdate()
	if err != nil {
		// we also get an error on a "no update" result, so this is fine
		log.Println("update-engine returned error:", err.Error())
	}

	// TODO run configure
	err = setupUtilityScripts(rootDir, configureExtractDir)
	if err != nil {
		return err
	}

	// END TODO run configure
	err = pullAllImages(releaseData, maxPullers)
	if err != nil {
		return err
	}

	err = parseAllTemplates(rootDir, configureExtractDir, releaseData)
	if err != nil {
		return err
	}

	err = cleanupSystemd(rootDir)
	if err != nil {
		return err
	}

	setStatus("done", nil, nil)

	// TODO allow to skip the reboot
	log.Println("Triggering a reboot")
	rebootCmd := exec.Command("/usr/sbin/shutdown", "--reboot", "1")
	rebootCmd.Run()

	return nil
}

func setupPaths(rootPrefix string) error {
	requiredPaths := []string{
		"/etc/protonet",
{'fraction_non_alphanumeric': 0.12516644474034622, 'fraction_numerical': 0.0039946737683089215, 'mean_word_length': 4.2526223776223775, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1408330', 'n_tokens_mistral': 2082, 'n_tokens_neox': 1976, 'n_words': 569}