2014-07-25 16:49:16 +02:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
# encoding: utf-8
|
|
|
|
# === This file is part of Calamares - <http://github.com/calamares> ===
|
|
|
|
#
|
|
|
|
# Copyright 2014, Teo Mrnjavac <teo@kde.org>
|
|
|
|
#
|
|
|
|
# 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 os
|
2014-07-28 17:46:56 +02:00
|
|
|
import shutil
|
2014-07-25 16:49:16 +02:00
|
|
|
import subprocess
|
2014-07-28 11:35:24 +02:00
|
|
|
import tempfile
|
2014-07-28 12:17:06 +02:00
|
|
|
from collections import namedtuple
|
2014-07-25 16:49:16 +02:00
|
|
|
|
|
|
|
from libcalamares import *
|
2014-07-28 11:55:55 +02:00
|
|
|
from filecopy import FileCopy
|
2014-07-25 16:49:16 +02:00
|
|
|
|
2014-07-28 12:17:06 +02:00
|
|
|
UnpackEntry = namedtuple( 'UnpackEntry', [ 'source', 'destination', 'sourceDir' ] )
|
|
|
|
UnpackStatusEntry = namedtuple( 'UnpackStatusEntry', [ 'copied', 'total' ] )
|
2014-07-25 16:49:16 +02:00
|
|
|
|
|
|
|
class UnsquashOperation:
|
|
|
|
def __init__( self, unpack ):
|
|
|
|
self.unpacklist = unpack
|
|
|
|
self.unpackstatus = dict()
|
|
|
|
for entry in unpack:
|
2014-07-28 12:17:06 +02:00
|
|
|
self.unpackstatus[ entry.source ] = UnpackStatusEntry( copied=0, total=0 )
|
2014-07-25 16:49:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
def updateCopyProgress( self, source, nfiles ):
|
|
|
|
if source in self.unpackstatus:
|
2014-07-28 12:17:06 +02:00
|
|
|
self.unpackstatus[ source ].copied = nfiles
|
2014-07-25 16:49:16 +02:00
|
|
|
self.reportProgress()
|
|
|
|
|
|
|
|
|
|
|
|
def reportProgress( self ):
|
|
|
|
progress = float( 0 )
|
2014-07-28 12:17:06 +02:00
|
|
|
for statusEntry in self.unpackstatus:
|
2014-07-28 17:51:35 +02:00
|
|
|
if statusEntry.total == 0:
|
2014-07-25 16:49:16 +02:00
|
|
|
continue
|
|
|
|
|
2014-07-28 17:51:35 +02:00
|
|
|
partialProgress = 0.05 # Having a total !=0 gives 5%
|
|
|
|
|
2014-07-28 12:17:06 +02:00
|
|
|
partialProgress += 0.95 * ( statusEntry.copied / float( statusEntry.total ) )
|
2014-07-25 16:49:16 +02:00
|
|
|
progress += partialProgress / len( self.unpackstatus )
|
|
|
|
|
|
|
|
job.setprogress( progress )
|
|
|
|
|
|
|
|
|
|
|
|
def run( self ):
|
2014-07-28 11:35:24 +02:00
|
|
|
sourceMountPath = tempfile.mkdtemp()
|
|
|
|
try:
|
|
|
|
for entry in self.unpacklist:
|
2014-07-28 17:46:56 +02:00
|
|
|
sqfsList = subprocess.check_output( [ "unsquashfs", "-l", entry.source ] )
|
|
|
|
filesCount = sqfsList.splitlines().count()
|
|
|
|
self.unpackstatus[ entry.source ].total = filesCount
|
|
|
|
|
|
|
|
imgBaseName = os.path.splitext( os.path.basename( entry.source ) )[ 0 ]
|
|
|
|
imgMountDir = sourceMountPath + os.sep + imgBaseName
|
|
|
|
os.mkdir( imgMountDir )
|
|
|
|
entry.sourceDir = imgMountDir
|
|
|
|
self.reportProgress()
|
|
|
|
self.unsquashImage( entry )
|
2014-07-28 11:35:24 +02:00
|
|
|
finally:
|
2014-07-28 17:46:56 +02:00
|
|
|
shutil.rmtree( sourceMountPath )
|
2014-07-25 16:49:16 +02:00
|
|
|
|
2014-07-28 12:17:06 +02:00
|
|
|
|
2014-07-25 16:49:16 +02:00
|
|
|
def unsquashImage( self, entry ):
|
2014-07-28 17:46:56 +02:00
|
|
|
subprocess.check_call( [ "mount", entry.source, entry.sourceDir, "-t", "squashfs", "-o", "loop" ] )
|
2014-07-28 11:35:24 +02:00
|
|
|
try:
|
2014-07-28 12:17:06 +02:00
|
|
|
t = FileCopy( entry.sourceDir, entry.destination, self.reportProgress )
|
2014-07-28 11:55:55 +02:00
|
|
|
t.run()
|
2014-07-28 11:35:24 +02:00
|
|
|
finally:
|
2014-07-28 12:17:06 +02:00
|
|
|
subprocess.check_call( [ "umount", "-l", entry.sourceDir ] )
|
2014-07-25 16:49:16 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run():
|
|
|
|
# from globalStorage: rootMountPoint
|
|
|
|
# from job.configuration:
|
|
|
|
# the path to where to mount the source image(s) for copying
|
|
|
|
# an ordered list of unpack mappings for sqfs file <-> target dir relative
|
|
|
|
# to rootMountPoint, e.g.:
|
|
|
|
# configuration:
|
|
|
|
# unpack:
|
|
|
|
# - source: "/path/to/squashfs/image.sqfs"
|
|
|
|
# destination: ""
|
|
|
|
# - source: "/path/to/another/image.sqfs"
|
|
|
|
# destination: ""
|
|
|
|
|
|
|
|
rootMountPoint = globalStorage.value( "rootMountPoint" )
|
2014-07-28 17:03:22 +02:00
|
|
|
if not rootMountPoint:
|
|
|
|
return ( "No mount point for root partition in GlobalStorage",
|
|
|
|
"GlobalStorage does not contain a \"rootMountPoint\" key, doing nothing" )
|
|
|
|
if not os.path.exists( rootMountPoint ):
|
|
|
|
return ( "Bad mount point for root partition in GlobalStorage",
|
|
|
|
"GlobalStorage[\"rootMountPoint\"] is \"{}\", which does not exist, doing nothing".format( rootMountPoint ) )
|
2014-07-25 16:49:16 +02:00
|
|
|
unpack = list()
|
|
|
|
|
|
|
|
for entry in job.configuration[ "unpack" ]:
|
|
|
|
source = os.path.abspath( entry[ "source" ] )
|
|
|
|
destination = os.path.abspath( os.path.join( rootMountPoint, entry[ "destination" ] ) )
|
|
|
|
|
|
|
|
if not os.path.isfile( source ) or not os.path.isdir( destination ):
|
2014-07-28 17:03:22 +02:00
|
|
|
return ( "Bad source or destination",
|
|
|
|
"source=\"{}\"\ndestination=\"{}\"".format( source, destination ) )
|
2014-07-25 16:49:16 +02:00
|
|
|
|
2014-07-28 12:17:06 +02:00
|
|
|
unpack.append( UnpackEntry( source, destination ) )
|
2014-07-25 16:49:16 +02:00
|
|
|
|
|
|
|
unsquashop = UnsquashOperation( unpack )
|
|
|
|
return unsquashop.run()
|