1 Commits

Author SHA1 Message Date
Jay Larson
6b62f87bf6 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!)
2018-01-17 09:25:06 -06:00
10 changed files with 880 additions and 294 deletions

View File

@@ -10,7 +10,9 @@
DEPENDS = binutils,coreutils,gzip,perl>=5.20.0,tar DEPENDS = binutils,coreutils,gzip,perl>=5.20.0,tar
ARCH = x86_64 ARCH = x86_64
URL = URL = http://snaplinux.org
REPO = core
BRIEF = The Snaplinux package management system
DESC = The Snaplinux package management system DESC = The Snaplinux package management system
SNAPVER = 0 SNAPVER = 0

View File

@@ -48,10 +48,10 @@ my $commands = {
], ],
brief => 'List package info', brief => 'List package info',
help => [ help => [
"\t\tPKGNAME or FILE is required." "\t\tOne or more PKGNAME or FILE is required.\n"
. " A version string\n\t\t\t\tcan optionally" . "\t\t\t\tA version string can optionally"
. " be provided with the PKGNAME\n" . " be provided\n\t\t\t\twith PKGNAME"
. "\t\t\t\tas packagename=x.x.x\n", . " as packagename=x.x.x\n",
"\t\t\tAn optional target may be specified" "\t\t\tAn optional target may be specified"
. " to\n\t\t\t\tquery a separate directory" . " to\n\t\t\t\tquery a separate directory"
. "/file system" . "/file system"
@@ -150,6 +150,17 @@ my $commands = {
"\t\t\t\tProceed without prompting" "\t\t\t\tProceed without prompting"
] ]
}, },
revdep => {
options => [
'<PKGNAME>',
'[-t TARGET]'
],
brief => 'List installed packages that depend on <PKGNAME>',
help => [
"\t\t\tPKGNAME is required\n",
"\t\t\tAn optional target may be specified"
]
},
search => { search => {
options => [ options => [
'[STRING[=VER]]', '[STRING[=VER]]',
@@ -167,14 +178,16 @@ my $commands = {
}, },
source => { source => {
options => [ options => [
'<PKGNAME[=VER]>' '<PKGNAME[=VER]>',
'[-l]'
], ],
brief => 'Retrieve package source', brief => 'Retrieve package source',
help => [ help => [
"\t\tPKGNAME is required." "\t\tPKGNAME is required."
. " A version string\n\t\t\t\tcan optionally" . " A version string\n\t\t\t\tcan optionally"
. " be provided with the PKGNAME\n" . " 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 => { upgrade => {
@@ -227,14 +240,12 @@ sub commandhelp {
my $options = $commands->{$command}{'options'}; my $options = $commands->{$command}{'options'};
my $help = $commands->{$command}{'help'}; 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"; print "$commands->{$command}{'brief'}\n\n";
for ( my $i = 0; $i <= $#{$options}; $i++ ) { for ( my $i = 0; $i <= $#{$options}; $i++ ) {
print " $options->[$i]$help->[$i]\n"; print " $options->[$i]$help->[$i]\n";
} }
print "\n";
} }
sub new { sub new {
@@ -248,7 +259,7 @@ sub help {
Snap->error( -1, "usage(): Invalid option '$ARGV[0]'" ); Snap->error( -1, "usage(): Invalid option '$ARGV[0]'" );
} }
print "\nUsage: $0 <COMMAND> <ARGS>\n\n" print "Usage: $0 <COMMAND> <ARGS>\n\n"
. "snap is the Snaplinux package management utility\n\n" . "snap is the Snaplinux package management utility\n\n"
. "COMMANDS\n\n"; . "COMMANDS\n\n";
@@ -257,7 +268,7 @@ sub help {
} }
print "\nTo view more information for commands run:\n" print "\nTo view more information for commands run:\n"
. "snap <COMMAND> -h\n\n"; . "snap <COMMAND> -h\n";
} }
1; 1;

View File

@@ -1,9 +1,11 @@
dirs: dirs:
install -d -v -m 755 $(DESTDIR)/etc install -d -v -m 755 $(DESTDIR)/etc/snap.d
install -d -v -m 755 $(DESTDIR)/usr/{bin,share/snap} 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 install -d -v -m 755 $(DESTDIR)/usr/lib/perl5/vendor_perl/5.24.0/Snap
files: 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 snap $(DESTDIR)/usr/bin/snap
install -v -m 755 snapinstall $(DESTDIR)/usr/bin/snapinstall install -v -m 755 snapinstall $(DESTDIR)/usr/bin/snapinstall
install -v -m 644 Makefile.skel \ install -v -m 644 Makefile.skel \

View File

@@ -8,9 +8,65 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # 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 = ARCH =
DEPENDS =
BUILDDEPS =
SRCPKG =
URL = URL =
REPO =
BRIEF = BRIEF =
DESC = DESC =
SNAPVER = SNAPVER =
@@ -50,6 +106,11 @@ $(SRCDIR)/config.log: $(SRCDIR)/configure
--host=x86_64-snap-linux-gnu \ --host=x86_64-snap-linux-gnu \
--target=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 $(SRCDIR)/binfile: $(SRCDIR)/config.log
@cd $(SRCDIR) && make @cd $(SRCDIR) && make

View File

@@ -8,42 +8,69 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
export SHELL := /bin/bash
PWD := $(shell pwd) PWD := $(shell pwd)
SNAPDIR = $(PWD)/SNAP SNAPDIR = $(PWD)/SNAP
ROOT = $(PWD)/ROOT ROOT = $(PWD)/ROOT
# This will set PACKAGE only if the package itself has # This will set PACKAGE to the name of the current working directory
# not provided a package name # if the package itself has not provided a package name
ifndef PACKAGE ifndef PACKAGE
PACKAGE := $(shell echo $(PWD)|sed 's/.*\///') PACKAGE := $(shell echo $(PWD)|sed 's/.*\///')
endif 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 # This defines the name of the package file unless
# specified # it is already specified in the package Makefile
ifndef PKGFILE ifndef PKGFILE
PKGFILE := $(PACKAGE)-$(VERSION).snap PKGFILE := $(PACKAGE)-$(VERSION).snap
endif 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 SNAPINFO = $(SNAPDIR)/snapinfo
MANIFEST = $(SNAPDIR)/manifest MANIFEST = $(SNAPDIR)/manifest
USHER = $(SNAPDIR)/usher USHER = $(SNAPDIR)/usher
FILES = $(SNAPDIR)/files.tar.gz FILES = $(SNAPDIR)/files.tar.gz
# If multiple packages are pulled from a single source # BRIEF is required.
# 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
ifndef SRCPKG ifndef BRIEF
SRCPKG := $(PACKAGE) $(error BRIEF is not set)
endif
# The following values must be set in the Makefile for the package
ifndef VERSION
$(error VERSION is not set)
endif endif
$(PKGFILE): $(SNAPINFO) $(FILES) $(PKGFILE): $(SNAPINFO) $(FILES)
@@ -65,11 +92,23 @@ $(SNAPINFO): $(MANIFEST)
$(eval BYTES := $(shell gzip -l $(FILES)|tail -1|awk '{print $$2}')) $(eval BYTES := $(shell gzip -l $(FILES)|tail -1|awk '{print $$2}'))
$(eval SHA256MAN := $(shell sha256sum $(MANIFEST)|awk '{print $$1}')) $(eval SHA256MAN := $(shell sha256sum $(MANIFEST)|awk '{print $$1}'))
@printf "name: $(PACKAGE)\nversion: $(VERSION)\n" > $(SNAPINFO) && \ @fields=( \
printf "depends: $(DEPENDS)\narch: $(ARCH)\n" >> $(SNAPINFO) && \ "name: $(PACKAGE)" \
printf "srcpkg: $(SRCPKG)\nbytes: $(BYTES)\n" >> $(SNAPINFO) && \ "version: $(VERSION)" \
printf "url: $(URL)\nsha256man: $(SHA256MAN)\n" >> $(SNAPINFO) && \ "arch: $(ARCH)" \
printf "brief: $(BRIEF)\ndescription: $(DESC)" >> $(SNAPINFO) "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): $(FILES)
@>$(MANIFEST) @>$(MANIFEST)
@@ -111,10 +150,13 @@ $(FILES): $(ROOT)
fi fi
@if [ -d $(ROOT)/usr/share/info ]; then \ @if [ -d $(ROOT)/usr/share/info ]; then \
find $(ROOT)/usr/share/info -type f -name \*.info| \ find $(ROOT)/usr/share/info -name '*.info' -o \
while read -r file; do \ -name '*.info-[0-9]*'|while read -r file; do \
gzip $$file; \ gzip $$file; \
done; \ done; \
if [ -f $(ROOT)/usr/share/info/dir ]; then \
rm -v $(ROOT)/usr/share/info/dir; \
fi; \
fi fi
@find $(ROOT) -type f | while read -r file; do \ @find $(ROOT) -type f | while read -r file; do \

View File

@@ -11,72 +11,82 @@ use Data::Dumper;
use parent 'Snap'; 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 # * arch: The architecture for which the package is built
# * brief: short desription of package # * brief: short desription of package
# * builddeps: dependencies for building the package
# * bytes: total bytes of installed package # * bytes: total bytes of installed package
# * depends: comma separated list of package dependencies # * depends: comma separated list of package dependencies
# * description: long description of package # * description: long description of package
# * name: package name # * name: package name
# * path: path to package, either local or repo file # * path: path to package, either local or repo file
# * source: source server
# * repo: repository where package is located, empty for # * repo: repository where package is located, empty for
# local file # local file
# * sha256: sha256sum for package file # * sha256: sha256sum for package file
# * sha256man: sha256sum for package manifest 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 # installed
# installing # installing
# removing # removing
# uninstalled # uninstalled
# upgrading # upgrading
# * status: The current status of the package, one of:
# * url: upstream source url # * url: upstream source url
# * version: version string # * 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 { sub new {
my $class = shift; my $class = shift;
my $package = shift; my $package = shift;
my $infofile = Snap->INSTDIR . "/$package/snapinfo"; my $infofile = Snap->INSTDIR . "/$package/snapinfo";
my $self = { my $self = {};
arch => '',
brief => '',
bytes => 0,
depends => '',
srcpkg => '',
description => '',
name => '',
source => '',
path => '',
repo => '',
sha256 => '',
sha256man => '',
status => '',
url => '',
version => ''
};
if ( ref( $package ) ) { if ( ref( $package ) ) {
foreach my $attr ( keys( %$self ) ) { foreach my $attr ( FIELDS ) {
$self->{$attr} = $package->{$attr}; $self->{$attr} = $package->{$attr};
} }
} }
elsif ( -f $package ) { elsif ( -f $package && Snap->issnap( $package ) ) {
my $sel = IO::Select->new(); my $sel = IO::Select->new();
my $stdout; my $stdout;
my $stderr; my $stderr;
my $stat; my $stat;
my $pid; my $pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR,
eval {
$pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR,
"/usr/bin/ar p $package snapinfo" ); "/usr/bin/ar p $package snapinfo" );
} || Snap->error( int( $! ), "open3(): /usr/bin/ar:"
. " $!" );
close( CHLDIN ); close( CHLDIN );
@@ -106,10 +116,8 @@ sub new {
$stat = $? >> 8; $stat = $? >> 8;
if ( $stat ) { if ( $stat ) {
$stderr =~ s/.*: //; Snap->error( $stat,
"Failed to read $package: $stderr" );
Snap->error( $stat, "Failed reading '$package':"
. " $stderr" );
} }
foreach ( split( /\n/, $stdout ) ) { foreach ( split( /\n/, $stdout ) ) {
@@ -150,6 +158,10 @@ sub new {
Snap->error( -2, "'$package': No such file or package found" ); Snap->error( -2, "'$package': No such file or package found" );
} }
if ( ! $self->{'srcpkg'} ) {
$self->{'srcpkg'} = $self->{'name'};
}
return( bless( $self, $class ) ); 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 { sub install {
my $self = shift; my $self = shift;
my $sources = shift; my $sources = shift;
@@ -498,6 +591,17 @@ sub install {
my $stat; my $stat;
local $| = 1; 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'}; $ENV{'VERSION'} = $self->{'version'};
if ( ! -f $self->{'path'} ) { if ( ! -f $self->{'path'} ) {
@@ -515,7 +619,7 @@ sub install {
} }
if ( ! -d $pkgdir ) { if ( ! -d $pkgdir ) {
mkdir( $pkgdir, 0644 ) || mkdir( $pkgdir, 0755 ) ||
Snap->error( int( $! ), "mkdir(): $pkgdir: $!" ); Snap->error( int( $! ), "mkdir(): $pkgdir: $!" );
} }
@@ -656,6 +760,10 @@ sub install {
Snap->error( int( $! ), "unlink(): $manifest: $!" ); Snap->error( int( $! ), "unlink(): $manifest: $!" );
} }
$self->infodir();
Snap->unlock();
print "Finished installing $self->{'name'}\n"; print "Finished installing $self->{'name'}\n";
} }
@@ -663,9 +771,14 @@ sub installed {
my $self = shift; my $self = shift;
my $infofile; my $infofile;
if ( ref( $self ) ) {
$infofile = Snap->INSTDIR . "/$self->{'name'}/snapinfo"; $infofile = Snap->INSTDIR . "/$self->{'name'}/snapinfo";
}
else {
$infofile = Snap->INSTDIR . "/$self/snapinfo";
}
if ( -f $infofile ) { if ( ref( $self ) && -f $infofile ) {
my $snapinfo; my $snapinfo;
open( SNAPINFO, "<$infofile" ) || open( SNAPINFO, "<$infofile" ) ||
@@ -685,6 +798,9 @@ sub installed {
return( 1 ); return( 1 );
} }
} }
elsif ( -f $infofile ) {
return( 1 );
}
return( 0 ); return( 0 );
} }
@@ -693,9 +809,9 @@ sub printbrief {
my $self = shift; my $self = shift;
if ( -t STDOUT ) { if ( -t STDOUT ) {
printf( '%-12.12s ', $self->{'name'} ); printf( '%-16.16s ', $self->{'name'} );
printf( '%-10.10s ', $self->{'version'} ); printf( '%-10.10s ', $self->{'version'} );
printf( '%.58s', $self->{'brief'} || $self->{'description'} ); printf( '%.52s', $self->{'brief'} || $self->{'description'} );
} }
else { else {
printf( '%-30.30s', $self->{'name'} ); printf( '%-30.30s', $self->{'name'} );
@@ -708,25 +824,8 @@ sub printbrief {
sub printself { sub printself {
my $self = shift; 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} ) { if ( $self->{$field} ) {
print "$field: $self->{$field}\n"; print "$field: $self->{$field}\n";
} }
@@ -738,18 +837,28 @@ sub remove {
my $pkgdir = Snap->INSTDIR . "/$self->{'name'}"; my $pkgdir = Snap->INSTDIR . "/$self->{'name'}";
my $snapinfo = "$pkgdir/snapinfo"; my $snapinfo = "$pkgdir/snapinfo";
my $manifest = "$pkgdir/manifest"; my $manifest = "$pkgdir/manifest";
my $usher = "$pkgdir/usher";
my $cnt = 0;
Snap->lock();
$self->files( { quiet => 1, all => 1 } ); $self->files( { quiet => 1, all => 1 } );
print "Removing $self->{'name'}... "; print "Removing $self->{'name'}=$self->{'version'}\n";
$self->usher( 'prerm' ); $self->usher( 'prerm' );
print "\e[?25l\r";
foreach ( @{$self->{'files'}} ) { foreach ( @{$self->{'files'}} ) {
if ( -f Snap->TARGET . "/$_" ) { if ( -f Snap->TARGET . "/$_" ) {
unlink( Snap->TARGET . "/$_" ) || Snap->error( unlink( Snap->TARGET . "/$_" ) || Snap->error(
int( $! ), "unlink(): " . Snap->TARGET int( $! ), "unlink(): " . Snap->TARGET
. "/$_: $!" ); . "/$_: $!" );
print "\e[K$_\r";
$cnt++;
} }
} }
@@ -760,7 +869,16 @@ sub remove {
unlink( $snapinfo ) || Snap->error( int( $! ), "unlink():" unlink( $snapinfo ) || Snap->error( int( $! ), "unlink():"
. " $snapinfo: $!" ); . " $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 { 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 ) { if ( ! -f $usher ) {
return; return;
} }
@@ -918,6 +1064,25 @@ sub usher {
waitpid( $pid, 0 ); waitpid( $pid, 0 );
$stat = $? >> 8; $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 { else {
exec( "$usher $action" ); exec( "$usher $action" );
} }
@@ -933,7 +1098,7 @@ sub usher {
# because the first shift gives you the class due to the # because the first shift gives you the class due to the
# fact that it must be called while specifying the namespace # 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 ); 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; 1;

View File

@@ -89,7 +89,7 @@ use constant VERFILE => eval {
} }
}; };
use constant { use constant {
VERSION => '0.11', VERSION => '0.12',
SNAPDIR => TARGET . '/var/lib/snap', SNAPDIR => TARGET . '/var/lib/snap',
PKGDIR => TARGET . '/var/lib/snap/packages', PKGDIR => TARGET . '/var/lib/snap/packages',
INSTDIR => TARGET . '/var/lib/snap/installed', INSTDIR => TARGET . '/var/lib/snap/installed',
@@ -105,7 +105,7 @@ use constant SNAPVER => eval {
return( $version ); 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/.*\///; $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 # 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{ $SIG{INT} = sub{
if ( TARGET ) {
virtfs( 'umount' ); virtfs( 'umount' );
}
print "\e[?25h\n"; print "\e[?25h\n";
@@ -182,9 +173,9 @@ sub chkyes {
chomp( $yes ); chomp( $yes );
if ( lc( $yes ) eq 'n' ){ if ( lc( $yes ) eq 'n' ){
print STDERR "\nAborting!\n\n"; print STDERR "\nAborting!\n";
exit 1; exit( 1 );
} }
elsif ( lc( $yes ne 'y' ) ){ elsif ( lc( $yes ne 'y' ) ){
print "Answer 'y' or 'n': "; print "Answer 'y' or 'n': ";
@@ -305,7 +296,9 @@ sub httpget {
PeerPort => 'http(80)', PeerPort => 'http(80)',
Proto => 'tcp' Proto => 'tcp'
) || Snap->error( int( $! ), "IO::Socket::Inet->new(): $!" ); ) || Snap->error( int( $! ), "IO::Socket::Inet->new(): $!" );
my $bytes; my $bytes = 0;
my @wheel = qw( - \ | / );
my $p = 0;
local $| = 1; local $| = 1;
@@ -326,7 +319,7 @@ sub httpget {
while ( <$sock> ) { while ( <$sock> ) {
if ( $dest ) { if ( $dest ) {
$bytes = ( stat( $dest ) )[7] || 0; $bytes += length( $_ );
} }
if ( ! $httpget{'dflag'} ) { if ( ! $httpget{'dflag'} ) {
@@ -377,24 +370,25 @@ sub httpget {
$httpget{'length'} * 100 ); $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 ( $p >= $#wheel ) {
if ( $i < $httpget{'pct'} / 5 ) { $p = 0;
print '*';
} }
else { else {
print ' '; $p++;
} }
} }
print "] $httpget{'pct'}%\r";
}
} }
if ( $dest ) { if ( $dest ) {
print "Retrieving $filename [********************] 100%" printf( "%-50.50s [%-20s] %s\e[?25h\n",
. "\e[?25h\n"; " * Downloaded $filename",
'*' x 20,
'100%' );
close( DEST ); 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 ( <FILE> ) {
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 { sub list {
my $listpackages = shift;
my $packages = {}; my $packages = {};
my $package = {}; my $package = {};
@@ -453,7 +486,8 @@ sub list {
. INSTDIR . ": $!" ); . INSTDIR . ": $!" );
foreach my $dir ( sort { $a cmp $b } readdir( DIR ) ) { 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; next;
} }
@@ -511,6 +545,13 @@ sub listfiles {
return( $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{ sub mkdirp{
( my $dir = shift ) =~ s/\/^//; ( my $dir = shift ) =~ s/\/^//;
my $mode = shift; my $mode = shift;
@@ -527,28 +568,58 @@ sub mkdirp{
### readconf() ############################################# ### readconf() #############################################
# #
# reads CONFFILE and builds a data structure with the # reads INI style files and builds a data structure with the
# parsed values. Only the 'sources' section is treated # parsed values.
# in a special way - it is pushed into an array to maintain #
# the order. This allows us to give priority to the topmost # The config file can 'include' additional directories.
# repositories # 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 { sub readconf {
my $conffile = shift || CONFFILE;
my $data = shift || {};
my $section = ''; my $section = '';
my $data = {};
my $line = 0; my $line = 0;
my $type;
open( FILE, "<", CONFFILE ) || Snap->error( int( $! ), if ( $conffile =~ /\.spt$/ ) {
"open: " . CONFFILE . ": $!\n" ); $type = 'template';
}
elsif ( $conffile =~ /\.conf$/ ) {
$type = 'config';
}
while ( <FILE> ) { open( my $fh, "<", $conffile ) || Snap->error( int( $! ),
"open(): $conffile: $!\n" );
while ( <$fh> ) {
chomp( $_ ); chomp( $_ );
if ( $_ =~ /^\s*#/ ) { if ( $_ =~ /^\s*#/ || $_ =~ /^$/ ) {
next; 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*/ ) { elsif ( $_ =~ /\s*\[(\S+)\]\s*/ ) {
$section = $1; $section = $1;
@@ -556,16 +627,22 @@ sub readconf {
$data->{$section} = []; $data->{$section} = [];
} }
} }
elsif ( $section eq 'sources' && elsif ( $section eq 'sources' ) {
$_ =~ /(\S+)\s*=\s*(.*)$/ ) {
push( @{$data->{$section}}, $_ ); push( @{$data->{$section}}, $_ );
} }
elsif ( $section && $type eq 'template' ) {
if ( ! $data->{'templates'}{$section} ) {
$data->{'templates'}{$section} = [];
}
push( @{$data->{'templates'}{$section}}, $_ );
}
elsif ( $_ =~ /(\S+)\s*=\s*(.*)$/ ) { elsif ( $_ =~ /(\S+)\s*=\s*(.*)$/ ) {
$data->{$section}{$1} = $2; $data->{$section}{$1} = $2;
} }
} }
close( FILE ); close( $fh );
return( $data ); return( $data );
} }
@@ -608,35 +685,6 @@ sub setup {
$chkfails++; $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 ) { if ( $target ) {
mkdir( TARGET, 0755 ) || Snap->error( int( $! ), "mkdir: $!" ); mkdir( TARGET, 0755 ) || Snap->error( int( $! ), "mkdir: $!" );
} }
@@ -736,6 +784,13 @@ sub termsize {
return( { row => $row, col => $col } ); return( { row => $row, col => $col } );
} }
sub unlock {
if ( -f LOCKFILE ) {
unlink( LOCKFILE ) || Snap->error( int( $! ), "unlink(): "
. LOCKFILE . ": Unable to remove lock file" );
}
}
### vercmp() ############################################### ### vercmp() ###############################################
# #
# This subroutine was basically copied verbatim from the # This subroutine was basically copied verbatim from the
@@ -812,6 +867,18 @@ sub vercmp {
@A <=> @B; @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 { sub virtfs {
my $command = shift; my $command = shift;
my $virtfs = { my $virtfs = {
@@ -832,7 +899,7 @@ sub virtfs {
} }
}; };
if ( ! TARGET ) { if ( $> || ! TARGET ) {
return; return;
} }
@@ -844,6 +911,7 @@ sub virtfs {
my $stat = 0; my $stat = 0;
my $pid; my $pid;
if ( ! -d $virtfs->{$fs}{'dir'} ) { if ( ! -d $virtfs->{$fs}{'dir'} ) {
next; next;
} }

59
SRC/snap/core.spt Normal file
View File

@@ -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

View File

@@ -6,7 +6,7 @@ use warnings;
use Snap; use Snap;
use Data::Dumper; use Data::Dumper;
my $command = shift( @ARGV ); my $command = shift( @ARGV ) || '';
my $conf = readconf(); my $conf = readconf();
my $commands = Snap::Commands->new(); my $commands = Snap::Commands->new();
my $sources = Snap::Sources->new( $conf->{'sources'} ); my $sources = Snap::Sources->new( $conf->{'sources'} );
@@ -48,15 +48,11 @@ elsif ( $command eq 'files' ) {
}; };
my $string = "@ARGV"; my $string = "@ARGV";
print "\n";
foreach my $arg ( @ARGV ) { foreach my $arg ( @ARGV ) {
my $package = Snap::Package->new( $arg ); my $package = Snap::Package->new( $arg );
$package->files( $opts ); $package->files( $opts );
} }
print "\n";
} }
elsif ( $command eq 'genpkg' ) { elsif ( $command eq 'genpkg' ) {
foreach my $arg ( @ARGV ) { foreach my $arg ( @ARGV ) {
@@ -67,14 +63,26 @@ elsif ( $command eq 'help' ) {
$commands->help(); $commands->help();
} }
elsif ( $command eq 'info' ) { 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 ) { foreach my $arg ( @ARGV ) {
my $package = Snap::Package->new( $arg ); my $package = Snap::Package->new( $arg );
if ( $cnt ) {
print "\n";
}
$package->printself(); $package->printself();
print "\n"; $cnt++;
} }
} }
elsif ( $command eq 'install' ) { elsif ( $command eq 'install' ) {
@@ -115,8 +123,6 @@ elsif ( $command eq 'install' ) {
} }
} }
print "\n";
$sources->readpkgs(); $sources->readpkgs();
#################################################### ####################################################
@@ -142,8 +148,8 @@ elsif ( $command eq 'install' ) {
my $package; my $package;
if ( ! -f $arg ) { if ( ! -f $arg ) {
my ( $name, $version ) = split( /(((<|>)=?|=)(.*))/, my ( $name, $version ) =
$arg ); split( /(((<|>)=?|=)(.*))/, $arg );
$opts->{'name'} = $name; $opts->{'name'} = $name;
$opts->{'version'} = $version; $opts->{'version'} = $version;
@@ -154,7 +160,7 @@ elsif ( $command eq 'install' ) {
} }
if ( ! $package ) { if ( ! $package ) {
Snap->error( -1, "$arg: No such package found" ); exit( -1 );
} }
if ( ! $opts->{'nodeps'} ) { if ( ! $opts->{'nodeps'} ) {
@@ -304,7 +310,9 @@ elsif ( $command eq 'install' ) {
. ". Continue? (y/n): "; . ". Continue? (y/n): ";
} }
if ( ! $opts->{'yes'} ) {
chkyes(); chkyes();
}
foreach my $package ( @$packages ) { foreach my $package ( @$packages ) {
if ( ! $virtfs ) { if ( ! $virtfs ) {
@@ -319,28 +327,51 @@ elsif ( $command eq 'install' ) {
if ( $virtfs ) { if ( $virtfs ) {
virtfs( 'umount' ); virtfs( 'umount' );
} }
print "\n";
} }
elsif ( $command eq 'list' ) { 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 ) ) ) { foreach my $package ( sort( keys( %$packages ) ) ) {
if ( $opts->{'verbose'} ) {
print "\n";
$packages->{$package}->printself();
}
else {
$packages->{$package}->printbrief(); $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' ) { elsif ( $command eq 'refresh' ) {
setup(); setup();
print "\n";
$sources->refresh(); $sources->refresh();
print "\n";
exit; exit;
foreach my $source ( @{$conf->{'sources'}} ) { foreach my $source ( @{$conf->{'sources'}} ) {
@@ -353,6 +384,7 @@ elsif ( $command eq 'refresh' ) {
} }
elsif ( $command eq 'reinstall' ) { elsif ( $command eq 'reinstall' ) {
my $opts = { my $opts = {
quiet => 1,
yes => eval { yes => eval {
for ( my $i = 0; $i <= $#ARGV; $i++ ) { for ( my $i = 0; $i <= $#ARGV; $i++ ) {
if ( $ARGV[$i] eq '-y' ) { if ( $ARGV[$i] eq '-y' ) {
@@ -363,15 +395,15 @@ elsif ( $command eq 'reinstall' ) {
} }
} }
}; };
my $termsize = Snap->termsize();
my $packages = []; my $packages = [];
my $virtfs = 0; my $virtfs = 0;
my $cnt = 0;
setup(); setup();
$sources->readpkgs(); $sources->readpkgs();
print "\n";
foreach my $pkgname ( @ARGV ) { foreach my $pkgname ( @ARGV ) {
my $package; my $package;
@@ -379,6 +411,10 @@ elsif ( $command eq 'reinstall' ) {
$package = Snap::Package->new( $pkgname ); $package = Snap::Package->new( $pkgname );
} }
else { else {
if ( ! $sources->{'installed'}{$pkgname} ) {
Snap->error( -1, "$pkgname not installed" );
}
$package = $sources->{'installed'}{$pkgname}; $package = $sources->{'installed'}{$pkgname};
$package = $sources->search( { $package = $sources->search( {
name => $package->{'name'}, 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*:\/\// ) { if ( $package->{'path'} =~ /https*:\/\// ) {
( my $filename = $package->{'path'} ) =~ s/.*\///; ( my $filename = $package->{'path'} ) =~ s/.*\///;
@@ -404,18 +434,18 @@ elsif ( $command eq 'reinstall' ) {
$package->{'path'} = Snap->PKGDIR . "/$filename"; $package->{'path'} = Snap->PKGDIR . "/$filename";
} }
$package->files( $opts );
push( @$packages, $package ); push( @$packages, $package );
} }
foreach my $package ( @$packages ) {
my $termsize = Snap->termsize();
my $cnt = 0;
foreach my $package ( sort { $a->{'name'} cmp $b->{'name'} } foreach my $package ( sort { $a->{'name'} cmp $b->{'name'} }
( @$packages ) ) { ( @$packages ) ) {
if ( ! $cnt ) { if ( ! $cnt ) {
print "The following packages will be" print "The following packages will be"
. " reinstalled:\n "; . " reinstalled:\n ";
$cnt++;
} }
if ( $termsize->{'col'} - ( length( if ( $termsize->{'col'} - ( length(
@@ -428,13 +458,13 @@ elsif ( $command eq 'reinstall' ) {
print "$package->{'name'} "; print "$package->{'name'} ";
$termsize->{'col'} -= length( $package->{'name'} ) + 1; $termsize->{'col'} -= length( $package->{'name'} ) + 1;
$cnt++;
}
} }
print "\n\nContinue? (y/n): "; print "\n\nContinue? (y/n): ";
if ( ! $opts->{'yes'} ) {
chkyes(); chkyes();
}
foreach my $package ( @$packages ) { foreach my $package ( @$packages ) {
if ( ! $virtfs ) { if ( ! $virtfs ) {
@@ -447,8 +477,6 @@ elsif ( $command eq 'reinstall' ) {
} }
virtfs( 'umount' ); virtfs( 'umount' );
print "\n";
} }
elsif ( $command eq 'remove' ) { elsif ( $command eq 'remove' ) {
my $opts = { my $opts = {
@@ -478,8 +506,6 @@ elsif ( $command eq 'remove' ) {
my $cnt = 0; my $cnt = 0;
my $termsize = Snap->termsize(); my $termsize = Snap->termsize();
print "\n";
$sources->readpkgs(); $sources->readpkgs();
foreach my $arg ( split( /\s/, $string ) ) { foreach my $arg ( split( /\s/, $string ) ) {
@@ -510,7 +536,13 @@ elsif ( $command eq 'remove' ) {
foreach my $package ( sort { $a->{'name'} cmp $b->{'name'} } foreach my $package ( sort { $a->{'name'} cmp $b->{'name'} }
( @$packages ) ) { ( @$packages ) ) {
if ( ! $cnt ) { 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( if ( $termsize->{'col'} - ( length(
@@ -531,21 +563,27 @@ elsif ( $command eq 'remove' ) {
print "\n\n" . human( $bytes ) . " will be recovered." print "\n\n" . human( $bytes ) . " will be recovered."
. " Continue? (y/n): "; . " Continue? (y/n): ";
if ( ! $opts->{'yes'} ) {
chkyes(); chkyes();
print "\n";
foreach my $package ( @$packages ) {
$package->remove( $sources );
} }
print "\n"; print "\n";
$cnt = 0;
foreach my $package ( @$packages ) {
if ( $cnt ) {
print "\n";
}
$package->remove( $sources );
$cnt++;
}
} }
elsif ( $command eq 'revdep' ) { elsif ( $command eq 'revdep' ) {
my $revdeps = []; my $revdeps = [];
print "\n";
$sources->readpkgs(); $sources->readpkgs();
foreach my $arg ( @ARGV ) { foreach my $arg ( @ARGV ) {
@@ -561,8 +599,6 @@ elsif ( $command eq 'revdep' ) {
if ( ! @$revdeps ) { if ( ! @$revdeps ) {
print "No reverse dependencies found\n"; print "No reverse dependencies found\n";
} }
print "\n";
} }
elsif ( $command eq 'search' ) { elsif ( $command eq 'search' ) {
my @attribs = qw( name version depends source repo description ); my @attribs = qw( name version depends source repo description );
@@ -607,19 +643,64 @@ elsif ( $command eq 'search' ) {
( $opts->{'string'} = $string ) =~ s/^ *| *$//g; ( $opts->{'string'} = $string ) =~ s/^ *| *$//g;
} }
print "\n";
if ( ! $sources->readpkgs() ) { if ( ! $sources->readpkgs() ) {
exit -1; exit( -1 );
} }
if ( ! $sources->search( $opts ) ) { 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 );
return( 1 );
}
}
},
quiet => 1
};
$sources->readpkgs();
if ( ! @ARGV ) {
Snap->error( 0, "'$command': You must supply an argument" );
$commands->commandhelp( 'source' );
exit( -1 );
} }
print "\n"; 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' ) { elsif ( $command eq 'verify' ) {
print "Not yet implemented\n";
exit( -1 );
foreach my $arg ( @ARGV ) { foreach my $arg ( @ARGV ) {
my $package = Snap::Package->new( $arg ); my $package = Snap::Package->new( $arg );
@@ -627,16 +708,20 @@ elsif ( $command eq 'verify' ) {
} }
} }
elsif ( $command eq 'version' ) { elsif ( $command eq 'version' ) {
print "\n" . Snap->VERSION . "\n\n"; print Snap->VERSION . "\n";
} }
elsif ( $command ) { elsif ( $command ) {
print "\n"; Snap->error( 0, "'$command': Invalid command" );
Snap->error( -1, "'$command': Invalid command" ); $commands->help();
exit( -1 );
} }
else { else {
Snap->error( 0, "You must supply a command" ); Snap->error( 0, "You must supply a command" );
$commands->help(); $commands->help();
exit( -1 );
} }

View File

@@ -11,6 +11,15 @@ setup();
my $conf = readconf(); my $conf = readconf();
my $sources = Snap::Sources->new( $conf->{'sources'} ); 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 = { my $opts = {
repo => 'core', repo => 'core',
quiet => 1 quiet => 1
@@ -19,82 +28,135 @@ my $corepkgs;
my $packages; my $packages;
my $virtfs = 0; my $virtfs = 0;
my $prepkgs = {}; my $prepkgs = {};
my $prelist = [ 'snap-base', 'bash', 'coreutils', 'glibc', my @prelist = qw(
'libacl', 'libattr', 'libcap', 'ncurses', 'readline', );
'tzdata', 'perl', 'initscripts' ]; my @packages = ();
print "\n";
if ( ! Snap->TARGET ) { if ( ! Snap->TARGET ) {
Snap->error( -1, 'A target must be specified with -t' ); Snap->error( -1, 'A target must be specified with -t' );
} }
$sources->readpkgs(); $sources->readpkgs();
$corepkgs = $sources->search( $opts );
for ( my $i = 0; $i <= $#$corepkgs; $i++ ) { foreach my $pkgname ( @{$conf->{'templates'}{'core'}} ) {
if ( ! $opts->{'nodeps'} ) { my $package = $sources->search( { name => $pkgname, quiet => 1 } );
print "Resolving dependencies for"
. " $corepkgs->[$i]{'name'}\n";
$corepkgs->[$i]->depends( $sources, $packages ); if ( $package->{'status'} && $package->{'status'} eq 'installed' ) {
next;
}
if ( $package->{'path'} =~ /https*:\/\// ) {
( my $filename = $package->{'path'} ) =~ s/.*\///;
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 );
$package->{'path'} = Snap->PKGDIR . "/$filename";
} }
else { else {
print "Ignoring dependencies for" Snap->error( -1, "$package->{'name'}:"
. " $corepkgs->[$i]{'name'}\n"; . " Unable to determine package path" );
}
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 ) { push( @packages, $package );
print "\n";
$prepkgs->{$package}->install();
} }
foreach my $package ( @$packages ) { foreach my $package ( @packages ) {
if ( ! $virtfs ) { $package->files( $opts );
$virtfs = virtfs( 'mount' );
}
print "\n"; print "\n";
$package->install(); $package->install();
} }
if ( $virtfs ) { if ( ! @packages ) {
my $pid; print "Nothing to do\n";
}
else {
print "Setting root password\n";
if ( $pid = fork() ) { if ( $> ) {
waitpid( $pid, 0 ); exec( "fakeroot fakechroot /usr/sbin/chroot "
. Snap->TARGET . " passwd root" );
} }
else { 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";