Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
4ceedf239c
@ -146,3 +146,12 @@ prompt-install: false
|
|||||||
#
|
#
|
||||||
# YAML: boolean.
|
# YAML: boolean.
|
||||||
dont-chroot: false
|
dont-chroot: false
|
||||||
|
|
||||||
|
# If this is set to true, the "Cancel" button will be disabled.
|
||||||
|
# This can be useful if when e.g. calamares is used as a post-install configuration
|
||||||
|
# tool and you require the user to go through all the configuration steps.
|
||||||
|
#
|
||||||
|
# Default is false.
|
||||||
|
#
|
||||||
|
# YAML: boolean.
|
||||||
|
disable-cancel: false
|
||||||
|
@ -81,6 +81,7 @@ Settings::Settings( const QString& settingsFilePath,
|
|||||||
, m_debug( debugMode )
|
, m_debug( debugMode )
|
||||||
, m_doChroot( true )
|
, m_doChroot( true )
|
||||||
, m_promptInstall( false )
|
, m_promptInstall( false )
|
||||||
|
, m_disableCancel( false )
|
||||||
{
|
{
|
||||||
cDebug() << "Using Calamares settings file at" << settingsFilePath;
|
cDebug() << "Using Calamares settings file at" << settingsFilePath;
|
||||||
QFile file( settingsFilePath );
|
QFile file( settingsFilePath );
|
||||||
@ -183,6 +184,7 @@ Settings::Settings( const QString& settingsFilePath,
|
|||||||
m_brandingComponentName = requireString( config, "branding" );
|
m_brandingComponentName = requireString( config, "branding" );
|
||||||
m_promptInstall = requireBool( config, "prompt-install", false );
|
m_promptInstall = requireBool( config, "prompt-install", false );
|
||||||
m_doChroot = !requireBool( config, "dont-chroot", false );
|
m_doChroot = !requireBool( config, "dont-chroot", false );
|
||||||
|
m_disableCancel = requireBool( config, "disable-cancel", false );
|
||||||
}
|
}
|
||||||
catch ( YAML::Exception& e )
|
catch ( YAML::Exception& e )
|
||||||
{
|
{
|
||||||
@ -245,5 +247,11 @@ Settings::doChroot() const
|
|||||||
return m_doChroot;
|
return m_doChroot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
Settings::disableCancel() const
|
||||||
|
{
|
||||||
|
return m_disableCancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,8 @@ public:
|
|||||||
|
|
||||||
bool doChroot() const;
|
bool doChroot() const;
|
||||||
|
|
||||||
|
bool disableCancel() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Settings* s_instance;
|
static Settings* s_instance;
|
||||||
|
|
||||||
@ -71,6 +73,7 @@ private:
|
|||||||
bool m_debug;
|
bool m_debug;
|
||||||
bool m_doChroot;
|
bool m_doChroot;
|
||||||
bool m_promptInstall;
|
bool m_promptInstall;
|
||||||
|
bool m_disableCancel;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -95,6 +95,10 @@ ViewManager::ViewManager( QObject* parent )
|
|||||||
this, &ViewManager::onInstallationFailed );
|
this, &ViewManager::onInstallationFailed );
|
||||||
connect( JobQueue::instance(), &JobQueue::finished,
|
connect( JobQueue::instance(), &JobQueue::finished,
|
||||||
this, &ViewManager::next );
|
this, &ViewManager::next );
|
||||||
|
|
||||||
|
if (Calamares::Settings::instance()->disableCancel())
|
||||||
|
m_quit->setVisible( false );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -282,9 +286,13 @@ ViewManager::updateButtonLabels()
|
|||||||
{
|
{
|
||||||
m_quit->setText( tr( "&Done" ) );
|
m_quit->setText( tr( "&Done" ) );
|
||||||
m_quit->setToolTip( tr( "The installation is complete. Close the installer." ) );
|
m_quit->setToolTip( tr( "The installation is complete. Close the installer." ) );
|
||||||
|
if (Calamares::Settings::instance()->disableCancel())
|
||||||
|
m_quit->setVisible( true );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (Calamares::Settings::instance()->disableCancel())
|
||||||
|
m_quit->setVisible( false );
|
||||||
m_quit->setText( tr( "&Cancel" ) );
|
m_quit->setText( tr( "&Cancel" ) );
|
||||||
m_quit->setToolTip( tr( "Cancel installation without changing the system." ) );
|
m_quit->setToolTip( tr( "Cancel installation without changing the system." ) );
|
||||||
}
|
}
|
||||||
|
181
src/modules/rawfs/main.py
Normal file
181
src/modules/rawfs/main.py
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# === This file is part of Calamares - <https://github.com/calamares> ===
|
||||||
|
#
|
||||||
|
# Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
|
||||||
|
#
|
||||||
|
# Calamares is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Calamares is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with Calamares. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import libcalamares
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import subprocess
|
||||||
|
from time import gmtime, strftime, sleep
|
||||||
|
from math import gcd
|
||||||
|
|
||||||
|
import gettext
|
||||||
|
_ = gettext.translation("calamares-python",
|
||||||
|
localedir=libcalamares.utils.gettext_path(),
|
||||||
|
languages=libcalamares.utils.gettext_languages(),
|
||||||
|
fallback=True).gettext
|
||||||
|
|
||||||
|
def pretty_name():
|
||||||
|
return _("Installing data.")
|
||||||
|
|
||||||
|
def lcm(a, b):
|
||||||
|
"""
|
||||||
|
Computes the Least Common Multiple of 2 numbers
|
||||||
|
"""
|
||||||
|
return a * b / gcd(a, b)
|
||||||
|
|
||||||
|
def get_device_size(device):
|
||||||
|
"""
|
||||||
|
Returns a filesystem's total size and block size in bytes.
|
||||||
|
For block devices, block size is the device's block size.
|
||||||
|
For other files (fs images), block size is 1 byte.
|
||||||
|
|
||||||
|
@param device: str
|
||||||
|
Absolute path to the device or filesystem image.
|
||||||
|
@return: tuple(int, int)
|
||||||
|
The filesystem's size and its block size.
|
||||||
|
"""
|
||||||
|
mode = os.stat(device).st_mode
|
||||||
|
if stat.S_ISBLK(mode):
|
||||||
|
basedevice = ""
|
||||||
|
partition = os.path.basename(device)
|
||||||
|
tmp = partition
|
||||||
|
while len(tmp) > 0:
|
||||||
|
tmp = tmp[:-1]
|
||||||
|
if os.path.exists("/sys/block/" + tmp):
|
||||||
|
basedevice = tmp
|
||||||
|
break
|
||||||
|
# Get device block size
|
||||||
|
file = open("/sys/block/" + basedevice + "/queue/hw_sector_size")
|
||||||
|
blocksize = int(file.readline())
|
||||||
|
file.close()
|
||||||
|
# Get partition size
|
||||||
|
file = open("/sys/block/" + basedevice + "/" + partition + "/size")
|
||||||
|
size = int(file.readline()) * blocksize
|
||||||
|
file.close()
|
||||||
|
else:
|
||||||
|
size = os.path.getsize(device)
|
||||||
|
blocksize = 1
|
||||||
|
|
||||||
|
return size, blocksize
|
||||||
|
|
||||||
|
class RawFSLowSpaceError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class RawFSItem:
|
||||||
|
__slots__ = ['source', 'destination', 'filesystem', 'resize']
|
||||||
|
|
||||||
|
def copy(self, current=0, total=1):
|
||||||
|
"""
|
||||||
|
Copies a raw filesystem on a disk partition, and grow it to the full destination
|
||||||
|
partition's size if required.
|
||||||
|
|
||||||
|
@param current: int
|
||||||
|
The index of the current item in the filesystems list
|
||||||
|
(used for progress reporting)
|
||||||
|
@param total: int
|
||||||
|
The number of items in the filesystems list
|
||||||
|
(used for progress reporting)
|
||||||
|
"""
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
libcalamares.utils.debug("Copying {} to {}".format(self.source, self.destination))
|
||||||
|
|
||||||
|
srcsize, srcblksize = get_device_size(self.source)
|
||||||
|
destsize, destblksize = get_device_size(self.destination)
|
||||||
|
|
||||||
|
if destsize < srcsize:
|
||||||
|
raise RawFSLowSpaceError
|
||||||
|
return
|
||||||
|
|
||||||
|
# Compute transfer block size (100x the LCM of the block sizes seems a good fit)
|
||||||
|
blksize = int(100 * lcm(srcblksize, destblksize))
|
||||||
|
|
||||||
|
# Execute copy
|
||||||
|
src = open(self.source, "rb")
|
||||||
|
dest = open(self.destination, "wb")
|
||||||
|
buffer = src.read(blksize)
|
||||||
|
while len(buffer) > 0:
|
||||||
|
dest.write(buffer)
|
||||||
|
count += len(buffer)
|
||||||
|
# Compute job progress
|
||||||
|
progress = ((count / srcsize) + (current)) / total
|
||||||
|
libcalamares.job.setprogress(progress)
|
||||||
|
# Read next data block
|
||||||
|
buffer = src.read(blksize)
|
||||||
|
src.close()
|
||||||
|
dest.close()
|
||||||
|
|
||||||
|
if self.resize:
|
||||||
|
if "ext" in self.filesystem:
|
||||||
|
libcalamares.utils.debug("Resizing filesystem on {}".format(self.destination))
|
||||||
|
subprocess.run(["e2fsck", "-f", "-y", self.destination])
|
||||||
|
subprocess.run(["resize2fs", self.destination])
|
||||||
|
|
||||||
|
def __init__(self, config, device, fs):
|
||||||
|
libcalamares.utils.debug("Adding an entry for raw copy of {} to {}".format(
|
||||||
|
config["source"], device))
|
||||||
|
self.source = config["source"]
|
||||||
|
# If source is a mount point, look for the actual device mounted on it
|
||||||
|
if os.path.ismount(self.source):
|
||||||
|
procmounts = open("/proc/mounts", "r")
|
||||||
|
for line in procmounts:
|
||||||
|
if self.source in line.split():
|
||||||
|
self.source = line.split()[0]
|
||||||
|
break
|
||||||
|
|
||||||
|
self.destination = device
|
||||||
|
self.filesystem = fs
|
||||||
|
try:
|
||||||
|
self.resize = bool(config["resize"])
|
||||||
|
except KeyError:
|
||||||
|
self.resize = False
|
||||||
|
|
||||||
|
def update_global_storage(item, gs):
|
||||||
|
for partition in gs:
|
||||||
|
if partition["device"] == item.destination:
|
||||||
|
ret = subprocess.run(["blkid", "-s", "UUID", "-o", "value", item.destination],
|
||||||
|
capture_output=True, text=True)
|
||||||
|
if ret.returncode == 0:
|
||||||
|
libcalamares.utils.debug("Setting {} UUID to {}".format(item.destination,
|
||||||
|
ret.stdout.rstrip()))
|
||||||
|
gs[gs.index(partition)]["uuid"] = ret.stdout.rstrip()
|
||||||
|
libcalamares.globalstorage.remove("partitions")
|
||||||
|
libcalamares.globalstorage.insert("partitions", gs)
|
||||||
|
|
||||||
|
def run():
|
||||||
|
"""Raw filesystem copy module"""
|
||||||
|
filesystems = list()
|
||||||
|
partitions = libcalamares.globalstorage.value("partitions")
|
||||||
|
|
||||||
|
for partition in partitions:
|
||||||
|
if partition["mountPoint"]:
|
||||||
|
for src in libcalamares.job.configuration["targets"]:
|
||||||
|
if src["mountPoint"] == partition["mountPoint"]:
|
||||||
|
filesystems.append(RawFSItem(src, partition["device"], partition["fs"]))
|
||||||
|
|
||||||
|
for item in filesystems:
|
||||||
|
try:
|
||||||
|
item.copy(filesystems.index(item), len(filesystems))
|
||||||
|
except RawFSLowSpaceError:
|
||||||
|
return ("Not enough free space",
|
||||||
|
"{} partition is too small to copy {} on it".format(item.destination, item.source))
|
||||||
|
update_global_storage(item, partitions)
|
||||||
|
|
||||||
|
return None
|
7
src/modules/rawfs/module.desc
Normal file
7
src/modules/rawfs/module.desc
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Module metadata file for block-copy jobmodule
|
||||||
|
# Syntax is YAML 1.2
|
||||||
|
---
|
||||||
|
type: "job"
|
||||||
|
name: "rawfs"
|
||||||
|
interface: "python"
|
||||||
|
script: "main.py"
|
24
src/modules/rawfs/rawfs.conf
Normal file
24
src/modules/rawfs/rawfs.conf
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# Configuration for the rawfs module: raw filesystem copy to a block device
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# To apply a custom partition layout, it has to be defined this way :
|
||||||
|
#
|
||||||
|
# targets:
|
||||||
|
# - mountPoint: /
|
||||||
|
# source: /
|
||||||
|
# - mountPoint: /home
|
||||||
|
# source: /images/home.img
|
||||||
|
# resize: true
|
||||||
|
# - mountPoint: /data
|
||||||
|
# source: /dev/mmcblk0p3
|
||||||
|
#
|
||||||
|
# For each target, the following attributes must be defined:
|
||||||
|
# * mountPoint: The mount point of the destination device on the installed system
|
||||||
|
# The corresponding block device will automatically be identified and used as the
|
||||||
|
# destination for the operation
|
||||||
|
# * source: The source filesystem; it can be the mount point of a locally (on the
|
||||||
|
# live system) mounted filesystem, a disk image, or a block device
|
||||||
|
# * resize (optional): Expand the destination filesystem to fill the whole
|
||||||
|
# partition at the end of the operation; this works only with ext filesystems
|
||||||
|
# for now
|
Loading…
Reference in New Issue
Block a user