From 6b62f87bf674889714acd29b6bd9286dc8c965fc Mon Sep 17 00:00:00 2001 From: Jay Larson Date: Wed, 17 Jan 2018 09:25:06 -0600 Subject: [PATCH] The following changes were made: * Cleaned up some output and variable assignments * Added additional error handling/output * Implemented 'source' command (git clones) * More variable requirements for Makefile.snaplinux * Package.pm is now more sane in dealing with the package object * Added chroot/fakechroot (will likely need further tweaking!) * Improved locking * Added ability to use templates for snapinstall (will be expanded!) --- Makefile | 4 +- SRC/snap/Commands.pm | 33 ++-- SRC/snap/Makefile | 6 +- SRC/snap/Makefile.skel | 65 +++++++- SRC/snap/Makefile.snaplinux | 86 +++++++--- SRC/snap/Package.pm | 312 +++++++++++++++++++++++++++++------- SRC/snap/Snap.pm | 216 ++++++++++++++++--------- SRC/snap/core.spt | 59 +++++++ SRC/snap/snap | 233 ++++++++++++++++++--------- SRC/snap/snapinstall | 160 ++++++++++++------ 10 files changed, 880 insertions(+), 294 deletions(-) create mode 100644 SRC/snap/core.spt diff --git a/Makefile b/Makefile index f91f00a..285f05f 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,9 @@ DEPENDS = binutils,coreutils,gzip,perl>=5.20.0,tar ARCH = x86_64 -URL = +URL = http://snaplinux.org +REPO = core +BRIEF = The Snaplinux package management system DESC = The Snaplinux package management system SNAPVER = 0 diff --git a/SRC/snap/Commands.pm b/SRC/snap/Commands.pm index 2193efc..76b6cd1 100644 --- a/SRC/snap/Commands.pm +++ b/SRC/snap/Commands.pm @@ -48,10 +48,10 @@ my $commands = { ], brief => 'List package info', help => [ - "\t\tPKGNAME or FILE is required." - . " A version string\n\t\t\t\tcan optionally" - . " be provided with the PKGNAME\n" - . "\t\t\t\tas packagename=x.x.x\n", + "\t\tOne or more PKGNAME or FILE is required.\n" + . "\t\t\t\tA version string can optionally" + . " be provided\n\t\t\t\twith PKGNAME" + . " as packagename=x.x.x\n", "\t\t\tAn optional target may be specified" . " to\n\t\t\t\tquery a separate directory" . "/file system" @@ -150,6 +150,17 @@ my $commands = { "\t\t\t\tProceed without prompting" ] }, + revdep => { + options => [ + '', + '[-t TARGET]' + ], + brief => 'List installed packages that depend on ', + help => [ + "\t\t\tPKGNAME is required\n", + "\t\t\tAn optional target may be specified" + ] + }, search => { options => [ '[STRING[=VER]]', @@ -167,14 +178,16 @@ my $commands = { }, source => { options => [ - '' + '', + '[-l]' ], brief => 'Retrieve package source', help => [ "\t\tPKGNAME is required." . " A version string\n\t\t\t\tcan optionally" . " be provided with the PKGNAME\n" - . "\t\t\t\tas packagename=x.x.x" + . "\t\t\t\tas packagename=x.x.x\n", + "\t\t\t\tRetrieve the latest version" ] }, upgrade => { @@ -227,14 +240,12 @@ sub commandhelp { my $options = $commands->{$command}{'options'}; my $help = $commands->{$command}{'help'}; - print "\nsnap $command @{$commands->{$command}{'options'}}\n\n"; + print "snap $command @{$commands->{$command}{'options'}}\n\n"; print "$commands->{$command}{'brief'}\n\n"; for ( my $i = 0; $i <= $#{$options}; $i++ ) { print " $options->[$i]$help->[$i]\n"; } - - print "\n"; } sub new { @@ -248,7 +259,7 @@ sub help { Snap->error( -1, "usage(): Invalid option '$ARGV[0]'" ); } - print "\nUsage: $0 \n\n" + print "Usage: $0 \n\n" . "snap is the Snaplinux package management utility\n\n" . "COMMANDS\n\n"; @@ -257,7 +268,7 @@ sub help { } print "\nTo view more information for commands run:\n" - . "snap -h\n\n"; + . "snap -h\n"; } 1; diff --git a/SRC/snap/Makefile b/SRC/snap/Makefile index 8b53de4..4a3d6d4 100644 --- a/SRC/snap/Makefile +++ b/SRC/snap/Makefile @@ -1,9 +1,11 @@ dirs: - install -d -v -m 755 $(DESTDIR)/etc - install -d -v -m 755 $(DESTDIR)/usr/{bin,share/snap} + install -d -v -m 755 $(DESTDIR)/etc/snap.d + install -d -v -m 755 $(DESTDIR)/usr/bin + install -d -v -m 755 $(DESTDIR)/usr/share/snap install -d -v -m 755 $(DESTDIR)/usr/lib/perl5/vendor_perl/5.24.0/Snap files: + install -v -m 644 core.spt $(DESTDIR)/etc/snap.d/core.spt install -v -m 755 snap $(DESTDIR)/usr/bin/snap install -v -m 755 snapinstall $(DESTDIR)/usr/bin/snapinstall install -v -m 644 Makefile.skel \ diff --git a/SRC/snap/Makefile.skel b/SRC/snap/Makefile.skel index d48eb17..17d7c2a 100644 --- a/SRC/snap/Makefile.skel +++ b/SRC/snap/Makefile.skel @@ -8,10 +8,66 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -DEPENDS = +# Some, but not all of variables are required. The following list +# describes the required variables: +# +# * URL: The main website of the upstream project +# * REPO: The location of the package on the source pacakge +# server. This might be one of core, main, dev, or +# perhaps others. +# * BRIEF: Short description, should be 50 chars or less +# * SNAPVER: This is the package version. When a package is +# changed, but no changes are made to the source code +# this value should be increased. This would include +# things like usher being modified, changes to default +# configuration files, file permissions, etc. +# * ARCHIVE: The default commands that set this variable should +# work in most cases, but in some cases it may need +# to be modified. This variable should contain the +# path to the source of the package (./SRC/filename) +# * TYPE: This is probably not really needed due to the +# ability of gnu tar to figure it out on its own. +# Should probably be removed at some point. +# * SRCDIR: This is the name of the source directory after the +# package source is extracted. The default command +# should in most cases set this automatically. +# * PATCHDIR: This directory should be ./SRC/patches and is +# required, whether or not patches are used. +# * VERSION: This should be set automatically based on the +# version string in the source directory and SNAPVER. +# The default command here should work in many cases, +# but certain packages may need to use a different +# method. +# +# Variables that aren't required: +# +# * ARCH: This should be populated for packages which contain +# compiled binaries. If it is not populated the ARCH +# will be set to 'noarch'. +# * DEPENDS: If any other packages are required for this package +# to function then they need to be listed here, +# preferably in alphabetical order. +# * BUILDDEPS: Any package beyond packages from the core repo +# need to be listed here. The idea is that we +# can automate building and testing packages +# from clean core systems. The core repo is +# intended to include only the base minimum +# packages which provide a functional system. +# * SRCPKG: By default this is populated automatically with +# the name of the package (current directory). If +# the source package is used to generate multiple +# packages then this variable should contain the +# name of the git repo that tracks the source. +# * DESC: This is to be used to provide a longer description +# of the package. + ARCH = +DEPENDS = +BUILDDEPS = +SRCPKG = URL = -BRIEF = +REPO = +BRIEF = DESC = SNAPVER = @@ -50,6 +106,11 @@ $(SRCDIR)/config.log: $(SRCDIR)/configure --host=x86_64-snap-linux-gnu \ --target=x86_64-snap-linux-gnu +# binfile should be replaced with a file generated by the +# make process. It won't really break anything if not +# set to a valid file, but the source make process will +# be re-executed even if it isn't necessary + $(SRCDIR)/binfile: $(SRCDIR)/config.log @cd $(SRCDIR) && make diff --git a/SRC/snap/Makefile.snaplinux b/SRC/snap/Makefile.snaplinux index 872bec4..a74f186 100644 --- a/SRC/snap/Makefile.snaplinux +++ b/SRC/snap/Makefile.snaplinux @@ -8,42 +8,69 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. +export SHELL := /bin/bash + PWD := $(shell pwd) SNAPDIR = $(PWD)/SNAP ROOT = $(PWD)/ROOT -# This will set PACKAGE only if the package itself has -# not provided a package name +# This will set PACKAGE to the name of the current working directory +# if the package itself has not provided a package name ifndef PACKAGE PACKAGE := $(shell echo $(PWD)|sed 's/.*\///') endif +# If VERSION is not set then we must fail + +ifndef VERSION +$(error VERSION is not set) +endif + # This defines the name of the package file unless -# specified +# it is already specified in the package Makefile ifndef PKGFILE PKGFILE := $(PACKAGE)-$(VERSION).snap endif +# If ARCH is not set we will assume noarch + +ifndef ARCH +ARCH := noarch +endif + +# SRCPKG defines the git repo name from which the package +# is built. In many cases it should be the same as the +# package name, but in cases where multiple packages are +# built from the same source this is especially relevant. + +ifndef SRCPKG +SRCPKG := $(PACKAGE) +endif + +# URL is required - this should point to the upstream project + +ifndef URL +$(error URL is not set) +endif + +# REPO is required. This value is used to determine the +# location of the package on the package source server + +ifndef REPO +$(error REPO is not set) +endif + SNAPINFO = $(SNAPDIR)/snapinfo MANIFEST = $(SNAPDIR)/manifest USHER = $(SNAPDIR)/usher FILES = $(SNAPDIR)/files.tar.gz -# If multiple packages are pulled from a single source -# then that source needs to be specified in SRCPKG, but -# if we find that not to be supplied we're going to -# assume that the SRCPKG is the same as the PACKAGE +# BRIEF is required. -ifndef SRCPKG -SRCPKG := $(PACKAGE) -endif - -# The following values must be set in the Makefile for the package - -ifndef VERSION -$(error VERSION is not set) +ifndef BRIEF +$(error BRIEF is not set) endif $(PKGFILE): $(SNAPINFO) $(FILES) @@ -65,11 +92,23 @@ $(SNAPINFO): $(MANIFEST) $(eval BYTES := $(shell gzip -l $(FILES)|tail -1|awk '{print $$2}')) $(eval SHA256MAN := $(shell sha256sum $(MANIFEST)|awk '{print $$1}')) - @printf "name: $(PACKAGE)\nversion: $(VERSION)\n" > $(SNAPINFO) && \ - printf "depends: $(DEPENDS)\narch: $(ARCH)\n" >> $(SNAPINFO) && \ - printf "srcpkg: $(SRCPKG)\nbytes: $(BYTES)\n" >> $(SNAPINFO) && \ - printf "url: $(URL)\nsha256man: $(SHA256MAN)\n" >> $(SNAPINFO) && \ - printf "brief: $(BRIEF)\ndescription: $(DESC)" >> $(SNAPINFO) + @fields=( \ + "name: $(PACKAGE)" \ + "version: $(VERSION)" \ + "arch: $(ARCH)" \ + "depends: $(DEPENDS)" \ + "builddeps: $(BUILDDEPS)" \ + "srcpkg: $(SRCPKG)" \ + "bytes: $(BYTES)" \ + "url: $(URL)" \ + "repo: $(REPO)" \ + "sha256man: $(SHA256MAN)" \ + "brief: $(BRIEF)" \ + "description: $(DESC)" \ + ) && \ + for field in "$${fields[@]}"; do \ + printf "$$field\n"; \ + done > $(SNAPINFO) $(MANIFEST): $(FILES) @>$(MANIFEST) @@ -111,10 +150,13 @@ $(FILES): $(ROOT) fi @if [ -d $(ROOT)/usr/share/info ]; then \ - find $(ROOT)/usr/share/info -type f -name \*.info| \ - while read -r file; do \ + find $(ROOT)/usr/share/info -name '*.info' -o \ + -name '*.info-[0-9]*'|while read -r file; do \ gzip $$file; \ done; \ + if [ -f $(ROOT)/usr/share/info/dir ]; then \ + rm -v $(ROOT)/usr/share/info/dir; \ + fi; \ fi @find $(ROOT) -type f | while read -r file; do \ diff --git a/SRC/snap/Package.pm b/SRC/snap/Package.pm index 502be5c..a8f0080 100644 --- a/SRC/snap/Package.pm +++ b/SRC/snap/Package.pm @@ -11,72 +11,82 @@ use Data::Dumper; use parent 'Snap'; -### new() ################################################## +############################################################ # -# This creates a new package object. The attributes are: +# The FIELDS constant defines all available attributes for +# package files. The following is a brief description of +# each: # # * arch: The architecture for which the package is built # * brief: short desription of package +# * builddeps: dependencies for building the package # * bytes: total bytes of installed package # * depends: comma separated list of package dependencies # * description: long description of package # * name: package name # * path: path to package, either local or repo file -# * source: source server # * repo: repository where package is located, empty for # local file # * sha256: sha256sum for package file # * sha256man: sha256sum for package manifest file -# * status: The current status of the package, one of: +# * source: source server +# * srcpkg: name of git repo for package source +# * status: status of package currently one of: # installed # installing # removing # uninstalled # upgrading +# * status: The current status of the package, one of: # * url: upstream source url # * version: version string # ############################################################ +use constant FIELDS => qw( + name + version + arch + depends + builddeps + srcpkg + status + bytes + url + path + source + repo + sha256 + sha256man + brief + description + ); + +### new() ################################################## +# +# This creates a new package object. The attributes are +# defined in the FIELDS constant. +# +############################################################ + sub new { my $class = shift; my $package = shift; my $infofile = Snap->INSTDIR . "/$package/snapinfo"; - my $self = { - arch => '', - brief => '', - bytes => 0, - depends => '', - srcpkg => '', - description => '', - name => '', - source => '', - path => '', - repo => '', - sha256 => '', - sha256man => '', - status => '', - url => '', - version => '' - }; + my $self = {}; if ( ref( $package ) ) { - foreach my $attr ( keys( %$self ) ) { + foreach my $attr ( FIELDS ) { $self->{$attr} = $package->{$attr}; } } - elsif ( -f $package ) { + elsif ( -f $package && Snap->issnap( $package ) ) { my $sel = IO::Select->new(); my $stdout; my $stderr; my $stat; - my $pid; - - eval { - $pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR, + my $pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR, "/usr/bin/ar p $package snapinfo" ); - } || Snap->error( int( $! ), "open3(): /usr/bin/ar:" - . " $!" ); close( CHLDIN ); @@ -106,10 +116,8 @@ sub new { $stat = $? >> 8; if ( $stat ) { - $stderr =~ s/.*: //; - - Snap->error( $stat, "Failed reading '$package':" - . " $stderr" ); + Snap->error( $stat, + "Failed to read $package: $stderr" ); } foreach ( split( /\n/, $stdout ) ) { @@ -150,6 +158,10 @@ sub new { Snap->error( -2, "'$package': No such file or package found" ); } + if ( ! $self->{'srcpkg'} ) { + $self->{'srcpkg'} = $self->{'name'}; + } + return( bless( $self, $class ) ); } @@ -483,6 +495,87 @@ sub files { } } +############################################################ +# +# This just generates the dir directory file for info docs +# +############################################################ + +sub infodir { + my $self = shift; + my $infodir = Snap->TARGET . '/usr/share/info'; + my $infofiles = []; + + if ( ! @{$self->{'files'}} ) { + return(); + } + + foreach my $file ( sort( @{$self->{'files'}} ) ) { + if ( $file !~ /usr\/share\/info\/.*\.info*/ || + ! -f Snap->TARGET . "/$file" ) { + next; + } + + push( @$infofiles, Snap->TARGET . "/$file" ); + } + + if ( @$infofiles == 0 ) { + return(); + } + + print "Updating " . @$infofiles . " info/dir entries\n"; + + print "\e[?25l\r"; + + foreach my $file ( @$infofiles ) { + my $sel = IO::Select->new(); + my $stdout; + my $stderr; + my $stat; + my $pid; + + print "\e[K$file\r"; + + eval { + $pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR, + "install-info $file $infodir/dir" ); + } || Snap->error( 0, 'install-info failed' ); + + close( CHLDIN ); + + $sel->add( *CHLDOUT, *CHLDERR ); + + while ( my @fhs = $sel->can_read ) { + foreach my $fh ( @fhs ) { + if ( eof( $fh ) ) { + $sel->remove( $fh ); + + next; + } + + if ( fileno( $fh ) == fileno( *CHLDOUT ) ) { + $stdout .= <$fh>; + } + elsif ( fileno( $fh ) == fileno( *CHLDERR ) ) { + $stderr .= <$fh>; + } + } + } + + close( CHLDOUT ); + close( CHLDERR ); + + waitpid( $pid, 0 ); + $stat = $? >> 8; + + if ( $? ) { + Snap->error( 0, "install-info: $file: $stderr" ); + } + } + + print "\e[Kdone\e[?25h\r"; + } + sub install { my $self = shift; my $sources = shift; @@ -498,6 +591,17 @@ sub install { my $stat; local $| = 1; + #################################################### + # + # This should attempt to get an exclusive lock on + # a temporary lock file. If it fails lock() will + # assume this means that a snap process is already + # running and die. + # + #################################################### + + Snap->lock(); + $ENV{'VERSION'} = $self->{'version'}; if ( ! -f $self->{'path'} ) { @@ -515,7 +619,7 @@ sub install { } if ( ! -d $pkgdir ) { - mkdir( $pkgdir, 0644 ) || + mkdir( $pkgdir, 0755 ) || Snap->error( int( $! ), "mkdir(): $pkgdir: $!" ); } @@ -656,6 +760,10 @@ sub install { Snap->error( int( $! ), "unlink(): $manifest: $!" ); } + $self->infodir(); + + Snap->unlock(); + print "Finished installing $self->{'name'}\n"; } @@ -663,9 +771,14 @@ sub installed { my $self = shift; my $infofile; - $infofile = Snap->INSTDIR . "/$self->{'name'}/snapinfo"; + if ( ref( $self ) ) { + $infofile = Snap->INSTDIR . "/$self->{'name'}/snapinfo"; + } + else { + $infofile = Snap->INSTDIR . "/$self/snapinfo"; + } - if ( -f $infofile ) { + if ( ref( $self ) && -f $infofile ) { my $snapinfo; open( SNAPINFO, "<$infofile" ) || @@ -685,6 +798,9 @@ sub installed { return( 1 ); } } + elsif ( -f $infofile ) { + return( 1 ); + } return( 0 ); } @@ -693,9 +809,9 @@ sub printbrief { my $self = shift; if ( -t STDOUT ) { - printf( '%-12.12s ', $self->{'name'} ); + printf( '%-16.16s ', $self->{'name'} ); printf( '%-10.10s ', $self->{'version'} ); - printf( '%.58s', $self->{'brief'} || $self->{'description'} ); + printf( '%.52s', $self->{'brief'} || $self->{'description'} ); } else { printf( '%-30.30s', $self->{'name'} ); @@ -708,25 +824,8 @@ sub printbrief { sub printself { my $self = shift; - my @fields = qw( - name - version - depends - srcpkg - arch - status - bytes - url - path - source - repo - sha256 - sha256man - brief - description - ); - foreach my $field ( @fields ) { + foreach my $field ( FIELDS ) { if ( $self->{$field} ) { print "$field: $self->{$field}\n"; } @@ -738,18 +837,28 @@ sub remove { my $pkgdir = Snap->INSTDIR . "/$self->{'name'}"; my $snapinfo = "$pkgdir/snapinfo"; my $manifest = "$pkgdir/manifest"; + my $usher = "$pkgdir/usher"; + my $cnt = 0; + + Snap->lock(); $self->files( { quiet => 1, all => 1 } ); - print "Removing $self->{'name'}... "; + print "Removing $self->{'name'}=$self->{'version'}\n"; $self->usher( 'prerm' ); + print "\e[?25l\r"; + foreach ( @{$self->{'files'}} ) { if ( -f Snap->TARGET . "/$_" ) { unlink( Snap->TARGET . "/$_" ) || Snap->error( int( $! ), "unlink(): " . Snap->TARGET . "/$_: $!" ); + + print "\e[K$_\r"; + + $cnt++; } } @@ -760,7 +869,16 @@ sub remove { unlink( $snapinfo ) || Snap->error( int( $! ), "unlink():" . " $snapinfo: $!" ); - print "DONE\n"; + if ( -f $usher ) { + unlink( $usher ) || Snap->error( int( $! ), "unlink():" + . " $usher: $!" ); + } + + print "\e[K$cnt files removed\e[?25h\n"; + + Snap->unlock(); + + print "Finished removing $self->{'name'}\n"; } sub revdeps { @@ -910,6 +1028,34 @@ sub usher { } } + #################################################### + # + # The usher script is forked and execed as a child + # process. For most packages the process will be + # executed in a chroot environment if a TARGET has + # been specified. + # + # The presence of coreutils should indicate an + # environment in which a chroot would be successful. + # We also check for bash or dash since usher + # should always be a shell script. This should be + # reduced to only checking for dash in the future + # since the intention is for all usher scripts + # to use /bin/sh which is expected to be dash. + # + # Certain packages (such as glibc) need to be able + # to execute usher without a chroot if a full + # environment is unavailable. + # + # For non-root users a fake chroot environment is + # created (if fakeroot and fakechroot is present). + # + # There is a bit of a hack here to undef TARGET + # so that usher scripts which still attempt to + # perform a chroot will not do so. + # + #################################################### + if ( ! -f $usher ) { return; } @@ -918,6 +1064,25 @@ sub usher { waitpid( $pid, 0 ); $stat = $? >> 8; } + elsif ( Snap->TARGET && installed( 'coreutils' ) && + installed( 'dash' ) ) { + my $cmd; + $usher = substr( $usher, length( Snap->TARGET ) ); + undef( $ENV{'TARGET'} ); + + if ( $> ) { + $ENV{'PATH'} = "$ENV{'PATH'}:/sbin:/usr/sbin"; + $cmd = "fakeroot fakechroot /usr/sbin/chroot " + . Snap->TARGET . " $usher $action"; + } + else { + chroot( Snap->TARGET ); + chdir( '/' ); + $cmd = "$usher $action"; + } + + exec( $cmd ); + } else { exec( "$usher $action" ); } @@ -933,7 +1098,7 @@ sub usher { # because the first shift gives you the class due to the # fact that it must be called while specifying the namespace # -# It has be modded on the central server only for now... +# It has been modded on the central server only for now... # ############################################################ @@ -946,4 +1111,33 @@ sub sha256 { return( $digest->hexdigest ); } +sub source { + my $self = shift; + my $gitcmd = "git clone git://git.snaplinux.org/$self->{'srcpkg'}.git"; + my $sel = IO::Select->new(); + my $stat; + my $pid; + + if ( $pid = fork() ) { + waitpid( $pid, 0 ); + $stat = $? >> 8; + } + else { + exec( $gitcmd ); + } + + if ( $stat ) { + Snap->error( $stat, "Failed to clone $self->{'srcpkg'}" ); + } + + if ( $pid = fork() ) { + waitpid( $pid, 0 ); + $stat = $? >> 8; + } + else { + chdir( $self->{'srcpkg'} ); + exec( "git checkout v$self->{'version'}" ); + } + } + 1; diff --git a/SRC/snap/Snap.pm b/SRC/snap/Snap.pm index 1039cc1..13a8d8b 100644 --- a/SRC/snap/Snap.pm +++ b/SRC/snap/Snap.pm @@ -89,7 +89,7 @@ use constant VERFILE => eval { } }; use constant { - VERSION => '0.11', + VERSION => '0.12', SNAPDIR => TARGET . '/var/lib/snap', PKGDIR => TARGET . '/var/lib/snap/packages', INSTDIR => TARGET . '/var/lib/snap/installed', @@ -105,7 +105,7 @@ use constant SNAPVER => eval { return( $version ); }; -use constant LOCKFILE => '/var/lock/snap'; +use constant LOCKFILE => TARGET . '/.snap'; ############################################################ # @@ -115,17 +115,6 @@ use constant LOCKFILE => '/var/lock/snap'; $0 =~ s/.*\///; -############################################################ -# -# Exit unless we can get exclusive lock -# -############################################################ - -open( LOCK, '>', LOCKFILE ) || Snap->error( int( $! ), "open(): " - . LOCKFILE . ": Unable to open lock file" ); -flock( LOCK, LOCK_EX|LOCK_NB ) || Snap->error( int( $! ), "flock(): " - . LOCKFILE . ": Unable to lock file" ); - ############################################################ # # Make sure we bring back the cursor if we're killed @@ -133,7 +122,9 @@ flock( LOCK, LOCK_EX|LOCK_NB ) || Snap->error( int( $! ), "flock(): " ############################################################ $SIG{INT} = sub{ - virtfs( 'umount' ); + if ( TARGET ) { + virtfs( 'umount' ); + } print "\e[?25h\n"; @@ -182,9 +173,9 @@ sub chkyes { chomp( $yes ); if ( lc( $yes ) eq 'n' ){ - print STDERR "\nAborting!\n\n"; + print STDERR "\nAborting!\n"; - exit 1; + exit( 1 ); } elsif ( lc( $yes ne 'y' ) ){ print "Answer 'y' or 'n': "; @@ -305,7 +296,9 @@ sub httpget { PeerPort => 'http(80)', Proto => 'tcp' ) || Snap->error( int( $! ), "IO::Socket::Inet->new(): $!" ); - my $bytes; + my $bytes = 0; + my @wheel = qw( - \ | / ); + my $p = 0; local $| = 1; @@ -326,7 +319,7 @@ sub httpget { while ( <$sock> ) { if ( $dest ) { - $bytes = ( stat( $dest ) )[7] || 0; + $bytes += length( $_ ); } if ( ! $httpget{'dflag'} ) { @@ -377,24 +370,25 @@ sub httpget { $httpget{'length'} * 100 ); } - print "Retrieving $filename ["; + printf( "%-50.50s [%-20s] %s\r", + " $wheel[$p] Downloading $filename", + '*' x int( $httpget{'pct'} / 5 ), + "$httpget{'pct'}%" ); - for ( my $i = 0; $i < 20; $i++ ){ - if ( $i < $httpget{'pct'} / 5 ) { - print '*'; - } - else { - print ' '; - } + if ( $p >= $#wheel ) { + $p = 0; + } + else { + $p++; } - - print "] $httpget{'pct'}%\r"; } } if ( $dest ) { - print "Retrieving $filename [********************] 100%" - . "\e[?25h\n"; + printf( "%-50.50s [%-20s] %s\e[?25h\n", + " * Downloaded $filename", + '*' x 20, + '100%' ); close( DEST ); } @@ -445,7 +439,46 @@ sub ismountpoint { } } +sub issnap { + my $class = shift; + my $file = shift; + my $lines = 0; + my $snapinfo = 0; + my $name = 0; + my $version = 0; + my $issnap = 0; + + open( FILE, "<$file" ) || Snap->error( -1, "open(): $file: $!" ); + + while ( ) { + if ( substr( $_, 0, 9 ) eq 'snapinfo/' ) { + $snapinfo++; + } + elsif ( substr( $_, 0, 5 ) eq 'name:' ) { + $name++; + } + elsif ( substr( $_, 0, 8 ) eq 'version:' ) { + $version++; + } + + $lines++; + + if ( $lines >= 12 ) { + last; + } + } + + close( FILE ) || Snap->error( -1, "close(): $file: $!" ); + + if ( $snapinfo && $name && $version ) { + return( 1 ); + } + + return( 0 ); + } + sub list { + my $listpackages = shift; my $packages = {}; my $package = {}; @@ -453,7 +486,8 @@ sub list { . INSTDIR . ": $!" ); foreach my $dir ( sort { $a cmp $b } readdir( DIR ) ) { - if ( $dir =~ /^\.{1,2}$/ || ! -f INSTDIR . "/$dir/snapinfo" ) { + if ( $dir =~ /^\.{1,2}$/ || ! -f INSTDIR . "/$dir/snapinfo" || + $listpackages->[0] && ! grep( $dir =~ /$_/, @$listpackages ) ) { next; } @@ -511,6 +545,13 @@ sub listfiles { return( $listfiles ); } +sub lock { + open( LOCK, '>', LOCKFILE ) || Snap->error( int( $! ), "open(): " + . LOCKFILE . ": Unable to open lock file" ); + flock( LOCK, LOCK_EX|LOCK_NB ) || Snap->error( int( $! ), "flock(): " + . LOCKFILE . ": Unable to lock file" ); + } + sub mkdirp{ ( my $dir = shift ) =~ s/\/^//; my $mode = shift; @@ -527,28 +568,58 @@ sub mkdirp{ ### readconf() ############################################# # -# reads CONFFILE and builds a data structure with the -# parsed values. Only the 'sources' section is treated -# in a special way - it is pushed into an array to maintain -# the order. This allows us to give priority to the topmost -# repositories +# reads INI style files and builds a data structure with the +# parsed values. +# +# The config file can 'include' additional directories. +# Files in these directories will be parsed and added to +# the the data structure. +# +# Files ending in .conf will be parsed into the root of the +# data structure while .spt (snap package template) files +# will be stored in 'templates' # ############################################################ sub readconf { + my $conffile = shift || CONFFILE; + my $data = shift || {}; my $section = ''; - my $data = {}; my $line = 0; + my $type; - open( FILE, "<", CONFFILE ) || Snap->error( int( $! ), - "open: " . CONFFILE . ": $!\n" ); + if ( $conffile =~ /\.spt$/ ) { + $type = 'template'; + } + elsif ( $conffile =~ /\.conf$/ ) { + $type = 'config'; + } - while ( ) { + open( my $fh, "<", $conffile ) || Snap->error( int( $! ), + "open(): $conffile: $!\n" ); + + while ( <$fh> ) { chomp( $_ ); - if ( $_ =~ /^\s*#/ ) { + if ( $_ =~ /^\s*#/ || $_ =~ /^$/ ) { next; } + elsif ( $_ =~ /\s*include\s+(.*)$/ ) { + foreach my $dir ( split( ' ', $1 ) ) { + opendir( my $dh, $dir ) || + Snap->error( int( $! ), + "opendir(): $dir: $!" ); + + while ( my $file = readdir( $dh ) ) { + if ( -f "$dir/$file" ) { + readconf( "$dir/$file", $data ); + } + } + + closedir( $dh ) || Snap->error( int( $! ), + "closedir(): $dir: $!" ); + } + } elsif ( $_ =~ /\s*\[(\S+)\]\s*/ ) { $section = $1; @@ -556,16 +627,22 @@ sub readconf { $data->{$section} = []; } } - elsif ( $section eq 'sources' && - $_ =~ /(\S+)\s*=\s*(.*)$/ ) { + elsif ( $section eq 'sources' ) { push( @{$data->{$section}}, $_ ); } + elsif ( $section && $type eq 'template' ) { + if ( ! $data->{'templates'}{$section} ) { + $data->{'templates'}{$section} = []; + } + + push( @{$data->{'templates'}{$section}}, $_ ); + } elsif ( $_ =~ /(\S+)\s*=\s*(.*)$/ ) { $data->{$section}{$1} = $2; } } - close( FILE ); + close( $fh ); return( $data ); } @@ -608,35 +685,6 @@ sub setup { $chkfails++; } - if ( $chkfails ) { - print "The following files/directories are missing: \n\n"; - } - else { - return; - } - - if ( $target ) { - print " " . TARGET . "\n"; - } - if ( $snapdir ) { - print " " . SNAPDIR . "\n"; - } - if ( $pkgdir ) { - print " " . PKGDIR . "\n"; - } - if ( $instdir ) { - print " " . INSTDIR . "\n"; - } - if ( $srcdir ) { - print " " . SRCDIR . "\n"; - } - - print "\n"; - - print "Create files/directories? (y/n): "; - - chkyes(); - if ( $target ) { mkdir( TARGET, 0755 ) || Snap->error( int( $! ), "mkdir: $!" ); } @@ -736,6 +784,13 @@ sub termsize { return( { row => $row, col => $col } ); } +sub unlock { + if ( -f LOCKFILE ) { + unlink( LOCKFILE ) || Snap->error( int( $! ), "unlink(): " + . LOCKFILE . ": Unable to remove lock file" ); + } + } + ### vercmp() ############################################### # # This subroutine was basically copied verbatim from the @@ -812,6 +867,18 @@ sub vercmp { @A <=> @B; } +### virtfs() ############################################### +# +# Need to try and figure out a solution for user installs +# +# The user may not be able to mount the virt filesystems, +# so perhaps it could do some kind of linking instead? +# +# Also remember you might want to move chroot out of usher +# and into here! We could also try to do fakechroot as well +# +############################################################ + sub virtfs { my $command = shift; my $virtfs = { @@ -832,7 +899,7 @@ sub virtfs { } }; - if ( ! TARGET ) { + if ( $> || ! TARGET ) { return; } @@ -844,6 +911,7 @@ sub virtfs { my $stat = 0; my $pid; + if ( ! -d $virtfs->{$fs}{'dir'} ) { next; } diff --git a/SRC/snap/core.spt b/SRC/snap/core.spt new file mode 100644 index 0000000..c5b6ec3 --- /dev/null +++ b/SRC/snap/core.spt @@ -0,0 +1,59 @@ +# +# These packages are the bare minimum necessary for a functional system. +# This file is required for snapinstall to function, so don't delete it! +# + +[core] +snap-base +dash +texinfo +coreutils +glibc +libacl +libattr +libcap +ncurses +readline +tzdata +perl +binutils +bzip2 +cpio +dhclient +e2fsprogs +ex +findutils +gawk +gdbm +gmp +grep +groff +gzip +iana-etc +iftools +inetutils +iproute2 +kmod +less +libgcc +libpipeline +libstdc++ +libzfs +linux-firmware +man-db +mkinitramfs +mpfr +net-tools +procps-ng +psmisc +sed +shadow +tar +snap +initscripts +sysklogd +sysvinit +tar +util-linux +xz +zlib diff --git a/SRC/snap/snap b/SRC/snap/snap index e69ff57..5d6605e 100755 --- a/SRC/snap/snap +++ b/SRC/snap/snap @@ -6,7 +6,7 @@ use warnings; use Snap; use Data::Dumper; -my $command = shift( @ARGV ); +my $command = shift( @ARGV ) || ''; my $conf = readconf(); my $commands = Snap::Commands->new(); my $sources = Snap::Sources->new( $conf->{'sources'} ); @@ -48,15 +48,11 @@ elsif ( $command eq 'files' ) { }; my $string = "@ARGV"; - print "\n"; - foreach my $arg ( @ARGV ) { my $package = Snap::Package->new( $arg ); $package->files( $opts ); } - - print "\n"; } elsif ( $command eq 'genpkg' ) { foreach my $arg ( @ARGV ) { @@ -67,14 +63,26 @@ elsif ( $command eq 'help' ) { $commands->help(); } elsif ( $command eq 'info' ) { - print "\n"; + my $cnt = 0; + if ( ! @ARGV ) { + Snap->error( 0, "'$command': You must supply an argument" ); + + $commands->commandhelp( 'info' ); + + exit( -1 ); + } + foreach my $arg ( @ARGV ) { my $package = Snap::Package->new( $arg ); + if ( $cnt ) { + print "\n"; + } + $package->printself(); - print "\n"; + $cnt++; } } elsif ( $command eq 'install' ) { @@ -115,8 +123,6 @@ elsif ( $command eq 'install' ) { } } - print "\n"; - $sources->readpkgs(); #################################################### @@ -142,8 +148,8 @@ elsif ( $command eq 'install' ) { my $package; if ( ! -f $arg ) { - my ( $name, $version ) = split( /(((<|>)=?|=)(.*))/, - $arg ); + my ( $name, $version ) = + split( /(((<|>)=?|=)(.*))/, $arg ); $opts->{'name'} = $name; $opts->{'version'} = $version; @@ -154,7 +160,7 @@ elsif ( $command eq 'install' ) { } if ( ! $package ) { - Snap->error( -1, "$arg: No such package found" ); + exit( -1 ); } if ( ! $opts->{'nodeps'} ) { @@ -304,7 +310,9 @@ elsif ( $command eq 'install' ) { . ". Continue? (y/n): "; } - chkyes(); + if ( ! $opts->{'yes'} ) { + chkyes(); + } foreach my $package ( @$packages ) { if ( ! $virtfs ) { @@ -319,28 +327,51 @@ elsif ( $command eq 'install' ) { if ( $virtfs ) { virtfs( 'umount' ); } - - print "\n"; } elsif ( $command eq 'list' ) { - my $packages = list(); + my $opts = { + verbose => eval { + for ( my $i = 0; $i <= $#ARGV; $i++ ) { + if ( $ARGV[$i] eq '-v' ) { + splice( @ARGV, $i, 1 ); - print "\n"; + return( 1 ); + } + } + } + }; + my $packages = list( \@ARGV ); foreach my $package ( sort( keys( %$packages ) ) ) { - $packages->{$package}->printbrief(); + if ( $opts->{'verbose'} ) { + print "\n"; + + $packages->{$package}->printself(); + } + else { + $packages->{$package}->printbrief(); + } } - print "\n"; + if ( ! keys( %$packages ) ) { + print "No installed packages found matching '@ARGV'\n"; + } + } +elsif ( $command eq 'purge' ) { + print "Not yet implemented\n"; + + exit( -1 ); + } +elsif ( $command eq 'rebuild' ) { + print "Not yet implemented\n"; + + exit( -1 ); } elsif ( $command eq 'refresh' ) { setup(); - print "\n"; - $sources->refresh(); - print "\n"; exit; foreach my $source ( @{$conf->{'sources'}} ) { @@ -353,6 +384,7 @@ elsif ( $command eq 'refresh' ) { } elsif ( $command eq 'reinstall' ) { my $opts = { + quiet => 1, yes => eval { for ( my $i = 0; $i <= $#ARGV; $i++ ) { if ( $ARGV[$i] eq '-y' ) { @@ -363,15 +395,15 @@ elsif ( $command eq 'reinstall' ) { } } }; + my $termsize = Snap->termsize(); my $packages = []; my $virtfs = 0; + my $cnt = 0; setup(); $sources->readpkgs(); - print "\n"; - foreach my $pkgname ( @ARGV ) { my $package; @@ -379,6 +411,10 @@ elsif ( $command eq 'reinstall' ) { $package = Snap::Package->new( $pkgname ); } else { + if ( ! $sources->{'installed'}{$pkgname} ) { + Snap->error( -1, "$pkgname not installed" ); + } + $package = $sources->{'installed'}{$pkgname}; $package = $sources->search( { name => $package->{'name'}, @@ -387,12 +423,6 @@ elsif ( $command eq 'reinstall' ) { } ); } - if ( ! $package ) { - print STDERR "Package '$pkgname' not installed\n"; - - next; - } - if ( $package->{'path'} =~ /https*:\/\// ) { ( my $filename = $package->{'path'} ) =~ s/.*\///; @@ -404,37 +434,37 @@ elsif ( $command eq 'reinstall' ) { $package->{'path'} = Snap->PKGDIR . "/$filename"; } + $package->files( $opts ); + push( @$packages, $package ); } - foreach my $package ( @$packages ) { - my $termsize = Snap->termsize(); - my $cnt = 0; + foreach my $package ( sort { $a->{'name'} cmp $b->{'name'} } + ( @$packages ) ) { + if ( ! $cnt ) { + print "The following packages will be" + . " reinstalled:\n "; - foreach my $package ( sort { $a->{'name'} cmp $b->{'name'} } - ( @$packages ) ) { - if ( ! $cnt ) { - print "The following packages will be" - . " reinstalled:\n "; - } - - if ( $termsize->{'col'} - ( length( - $package->{'name'} ) + 3 ) <= 0 ) { - print "\n "; - - $termsize = Snap->termsize(); - } - - print "$package->{'name'} "; - - $termsize->{'col'} -= length( $package->{'name'} ) + 1; $cnt++; } + + if ( $termsize->{'col'} - ( length( + $package->{'name'} ) + 3 ) <= 0 ) { + print "\n "; + + $termsize = Snap->termsize(); + } + + print "$package->{'name'} "; + + $termsize->{'col'} -= length( $package->{'name'} ) + 1; } print "\n\nContinue? (y/n): "; - chkyes(); + if ( ! $opts->{'yes'} ) { + chkyes(); + } foreach my $package ( @$packages ) { if ( ! $virtfs ) { @@ -447,8 +477,6 @@ elsif ( $command eq 'reinstall' ) { } virtfs( 'umount' ); - - print "\n"; } elsif ( $command eq 'remove' ) { my $opts = { @@ -478,8 +506,6 @@ elsif ( $command eq 'remove' ) { my $cnt = 0; my $termsize = Snap->termsize(); - print "\n"; - $sources->readpkgs(); foreach my $arg ( split( /\s/, $string ) ) { @@ -510,7 +536,13 @@ elsif ( $command eq 'remove' ) { foreach my $package ( sort { $a->{'name'} cmp $b->{'name'} } ( @$packages ) ) { if ( ! $cnt ) { - print "\nThe following packages will be removed:\n "; + print "\nThe following packages will be removed"; + + if ( Snap->TARGET ) { + print " from " . Snap->TARGET; + } + + print ":\n "; } if ( $termsize->{'col'} - ( length( @@ -531,21 +563,27 @@ elsif ( $command eq 'remove' ) { print "\n\n" . human( $bytes ) . " will be recovered." . " Continue? (y/n): "; - chkyes(); - - print "\n"; - - foreach my $package ( @$packages ) { - $package->remove( $sources ); + if ( ! $opts->{'yes'} ) { + chkyes(); } print "\n"; + + $cnt = 0; + + foreach my $package ( @$packages ) { + if ( $cnt ) { + print "\n"; + } + + $package->remove( $sources ); + + $cnt++; + } } elsif ( $command eq 'revdep' ) { my $revdeps = []; - print "\n"; - $sources->readpkgs(); foreach my $arg ( @ARGV ) { @@ -561,8 +599,6 @@ elsif ( $command eq 'revdep' ) { if ( ! @$revdeps ) { print "No reverse dependencies found\n"; } - - print "\n"; } elsif ( $command eq 'search' ) { my @attribs = qw( name version depends source repo description ); @@ -607,19 +643,64 @@ elsif ( $command eq 'search' ) { ( $opts->{'string'} = $string ) =~ s/^ *| *$//g; } - print "\n"; - if ( ! $sources->readpkgs() ) { - exit -1; + exit( -1 ); } if ( ! $sources->search( $opts ) ) { - exit -1; + exit( -1 ); } + } +elsif ( $command eq 'source' ) { + my $opts = { + latest => eval { + for ( my $i = 0; $i <= $#ARGV; $i++ ) { + if ( $ARGV[$i] eq '-l' ) { + splice( @ARGV, $i, 1 ); - print "\n"; + return( 1 ); + } + } + }, + quiet => 1 + }; + $sources->readpkgs(); + + if ( ! @ARGV ) { + Snap->error( 0, "'$command': You must supply an argument" ); + + $commands->commandhelp( 'source' ); + + exit( -1 ); + } + + foreach my $arg ( @ARGV ) { + my $package;# = Snap::Package->new( $arg ); + + if ( $sources->{'installed'}{$arg} && ! $opts->{'latest'} ) { + $package = $sources->{'installed'}{$arg}; + } + else { + my ( $name, $version ) = + split( /(((<|>)=?|=)(.*))/, $arg ); + $opts->{'name'} = $name; + $opts->{'version'} = $version; + $package = $sources->search( $opts ); + } + + $package->source(); + } + } +elsif ( $command eq 'upgrade' ) { + print "Not yet implemented\n"; + + exit( -1 ); } elsif ( $command eq 'verify' ) { + print "Not yet implemented\n"; + + exit( -1 ); + foreach my $arg ( @ARGV ) { my $package = Snap::Package->new( $arg ); @@ -627,16 +708,20 @@ elsif ( $command eq 'verify' ) { } } elsif ( $command eq 'version' ) { - print "\n" . Snap->VERSION . "\n\n"; + print Snap->VERSION . "\n"; } elsif ( $command ) { - print "\n"; + Snap->error( 0, "'$command': Invalid command" ); - Snap->error( -1, "'$command': Invalid command" ); + $commands->help(); + + exit( -1 ); } else { Snap->error( 0, "You must supply a command" ); $commands->help(); + + exit( -1 ); } diff --git a/SRC/snap/snapinstall b/SRC/snap/snapinstall index c9a7277..cce3562 100644 --- a/SRC/snap/snapinstall +++ b/SRC/snap/snapinstall @@ -11,6 +11,15 @@ setup(); my $conf = readconf(); my $sources = Snap::Sources->new( $conf->{'sources'} ); +my $container = eval { + for ( my $i = 0; $i <= $#ARGV; $i++ ) { + if ( $ARGV[$i] eq '-c' || $ARGV[$i] eq '--container' ) { + splice ( @ARGV, $i, 1 ); + + return( 1 ); + } + } + }; my $opts = { repo => 'core', quiet => 1 @@ -19,82 +28,135 @@ my $corepkgs; my $packages; my $virtfs = 0; my $prepkgs = {}; -my $prelist = [ 'snap-base', 'bash', 'coreutils', 'glibc', - 'libacl', 'libattr', 'libcap', 'ncurses', 'readline', - 'tzdata', 'perl', 'initscripts' ]; - -print "\n"; +my @prelist = qw( + ); +my @packages = (); if ( ! Snap->TARGET ) { Snap->error( -1, 'A target must be specified with -t' ); } $sources->readpkgs(); -$corepkgs = $sources->search( $opts ); -for ( my $i = 0; $i <= $#$corepkgs; $i++ ) { - if ( ! $opts->{'nodeps'} ) { - print "Resolving dependencies for" - . " $corepkgs->[$i]{'name'}\n"; +foreach my $pkgname ( @{$conf->{'templates'}{'core'}} ) { + my $package = $sources->search( { name => $pkgname, quiet => 1 } ); - $corepkgs->[$i]->depends( $sources, $packages ); - } - else { - print "Ignoring dependencies for" - . " $corepkgs->[$i]{'name'}\n"; + if ( $package->{'status'} && $package->{'status'} eq 'installed' ) { + next; } - push( @$packages, $corepkgs->[$i] ); - } + if ( $package->{'path'} =~ /https*:\/\// ) { + ( my $filename = $package->{'path'} ) =~ s/.*\///; -for ( my $i = 0; $i <= $#$packages; $i++ ) { - if ( $packages->[$i]{'path'} =~ /https*:\/\// ) { - ( my $filename = $packages->[$i]{'path'} ) =~ s/.*\///; - - if ( ! -f Snap->PKGDIR . "/$filename" ) { - Snap->httpget( $packages->[$i]{'path'}, - Snap->PKGDIR . "/$filename", 0644 ); + if ( -f "/var/lib/snap/packages/$filename" ) { + $package->{'path'} = "/var/lib/snap/packages/$filename"; } + elsif ( ! -f Snap->PKGDIR . "/$filename" ) { + Snap->httpget( $package->{'path'}, + Snap->PKGDIR . "/$filename", 0644 ); - $packages->[$i]{'path'} = Snap->PKGDIR . "/$filename"; + $package->{'path'} = Snap->PKGDIR . "/$filename"; + } + else { + Snap->error( -1, "$package->{'name'}:" + . " Unable to determine package path" ); + } } - - if ( grep( $_ eq $packages->[$i]{'name'}, @$prelist ) ) { - $prepkgs->{$packages->[$i]{'name'}} = $packages->[$i]; - - splice( @$packages, $i, 1 ); - $i--; - } + push( @packages, $package ); } -foreach my $package ( @$prelist ) { - print "\n"; - - $prepkgs->{$package}->install(); - } - -foreach my $package ( @$packages ) { - if ( ! $virtfs ) { - $virtfs = virtfs( 'mount' ); - } +foreach my $package ( @packages ) { + $package->files( $opts ); print "\n"; $package->install(); } -if ( $virtfs ) { - my $pid; +if ( ! @packages ) { + print "Nothing to do\n"; + } +else { + print "Setting root password\n"; - if ( $pid = fork() ) { - waitpid( $pid, 0 ); + if ( $> ) { + exec( "fakeroot fakechroot /usr/sbin/chroot " + . Snap->TARGET . " passwd root" ); } else { - exec( "chroot " . Snap->TARGET . " passwd" ); + exec ( "chroot " . Snap->TARGET . " passwd root" ); } } -virtfs( 'umount' ); +exit; -print "\n"; +#$sources->readpkgs(); +#$corepkgs = $sources->search( $opts ); + +#for ( my $i = 0; $i <= $#$corepkgs; $i++ ) { +# if ( ! $opts->{'nodeps'} ) { +# print "Resolving dependencies for" +# . " $corepkgs->[$i]{'name'}\n"; +# +# $corepkgs->[$i]->depends( $sources, $packages ); +# } +# else { +# print "Ignoring dependencies for" +# . " $corepkgs->[$i]{'name'}\n"; +# } +# +# push( @$packages, $corepkgs->[$i] ); +# } +# +#for ( my $i = 0; $i <= $#$packages; $i++ ) { +# if ( $packages->[$i]{'path'} =~ /https*:\/\// ) { +# ( my $filename = $packages->[$i]{'path'} ) =~ s/.*\///; +# +# if ( ! -f Snap->PKGDIR . "/$filename" ) { +# Snap->httpget( $packages->[$i]{'path'}, +# Snap->PKGDIR . "/$filename", 0644 ); +# } +# +# $packages->[$i]{'path'} = Snap->PKGDIR . "/$filename"; +# } +# +# +# if ( grep( $_ eq $packages->[$i]{'name'}, @$prelist ) ) { +# $prepkgs->{$packages->[$i]{'name'}} = $packages->[$i]; +# +# splice( @$packages, $i, 1 ); +# $i--; +# } +# } + +#foreach my $package ( @prelist ) { +# print "\n"; +# +# $prepkgs->{$package}->install(); +# } +# +#foreach my $package ( @$packages ) { +# if ( ! $virtfs ) { +# $virtfs = virtfs( 'mount' ); +# } +# +# print "\n"; +# +# $package->install(); +# } +# +#if ( $virtfs ) { +# my $pid; +# +# if ( $pid = fork() ) { +# waitpid( $pid, 0 ); +# } +# else { +# exec( "chroot " . Snap->TARGET . " passwd" ); +# } +# } +# +#virtfs( 'umount' ); +# +#print "\n";