9 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
Jay Larson
d4baa191d6 Declared $pid in snapinstall 2017-06-02 18:54:55 -05:00
Jay Larson
98c0ab336f The following changes were made:
* Updated Makefile.snaplinux to be more flexible with package names
  * Added bit to set root password in snapinstall
2017-06-02 18:49:47 -05:00
Jay Larson
cdbf4ed7d5 The following changes were made:
* Added ability to dump contents of package
  * Wrapped open3 in eval in Package.pm files()
  * Added :flock to Fcntl in Snap.pm
  * Added lock file to Snap.pm
  * Moved setup() under conditionals where appropriate in snap
2017-06-01 10:39:51 -05:00
Jay Larson
bfa1d110c4 The following changes were made
* Updated Makefile to get version from Snap.pm
  * Updated virtfs() in Snap.pm to properly check for dir with -d
2017-05-31 10:54:33 -05:00
Jay Larson
d306fe03ae The following changes were made:
* corrected issue in reinstall that prevented reinstall of package files
  * added version command
  * updated files() in Package.pm to accept both quiet and verbose options
  * added sha() to Snap.pm which will be used for verify function in future
  * corrected missing '=' in output for search() in Sources.pm
  * removed duplicate file (SRC/snapinstall)
2017-05-26 15:48:52 -05:00
Jay Larson
319401eb51 Corrected issue in assignment to $(SNAP) in Makefile.snaplinux 2017-05-22 14:46:14 -05:00
Jay Larson
4cd5b95d7e The following changes were made:
* Added snapinstall (missed on last check in)
  * Added reinstall functionality to snap
2017-05-22 14:15:38 -05:00
Jay Larson
6a9cce6b3f The following changes were made:
* removed usher
  * various cleanup in output
  * corrected issues with usher() in Package.pm, now using fork()/exec()
  * added snapinstall
  * made virtfs() more robust, will still attempt if fails
  * made strip a little more thoughtful in Makefile.snaplinux
2017-05-22 10:43:07 -05:00
11 changed files with 1391 additions and 343 deletions

View File

@@ -8,17 +8,19 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
DEPENDS = binutils,coreutils,gzip,perl=5.20.0,tar
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
ARCHIVE := ''
SRCDIR := $(PWD)/SRC/snap
PATCHDIR := $(PWD)/SRC/patches
VERSION := 0.4-0
MAKEINST = make install
VERSION := $(shell grep 'VERSION =>' SRC/snap/Snap.pm| \
sed "s/.*=> '\|',//g")-$(SNAPVER)
include /usr/share/snap/Makefile.snaplinux
@@ -29,7 +31,7 @@ $(ROOT): $(SRCDIR)/Makefile
mkdir -v $(ROOT); \
fi
@cd $(SRCDIR) && $(MAKEINST) DESTDIR=$(ROOT)
@cd $(SRCDIR) && make install DESTDIR=$(ROOT)
clean:
@rm -rvf $(ROOT) \

View File

@@ -1,43 +0,0 @@
#!/bin/bash
set -e
case $1 in
preinst)
exit 0
;;
postinst)
setpass=`cat ${TARGET}/etc/shadow|grep ^root|awk -F':' '{print $2}'`
if [ "$setpass" == 'SETPASS' ]; then
echo "Setting root password"
if [[ ${TARGET} ]]; then
if ! mountpoint ${TARGET}/dev; then
mount -o ro -t devtmpfs devtmpfs ${TARGET}/dev
chroot ${TARGET} passwd root
umount ${TARGET}/dev
else
chroot ${TARGET} passwd root
fi
else
passwd root
fi
fi
echo "Refreshing snap"
if [[ ${TARGET} ]]; then
chroot ${TARGET} snap refresh
else
snap refresh
fi
exit 0
;;
prerm)
exit 0
;;
postrm)
exit 0
;;
esac

View File

@@ -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 => [
'<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 => {
options => [
'[STRING[=VER]]',
@@ -167,14 +178,16 @@ my $commands = {
},
source => {
options => [
'<PKGNAME[=VER]>'
'<PKGNAME[=VER]>',
'[-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 => {
@@ -208,6 +221,11 @@ my $commands = {
. " separate\n\t\t\t\tdirectory/file system\n",
"\t\t\t\tProceed without prompting"
]
},
version => {
options => [],
brief => 'Display version information',
help => []
}
};
@@ -222,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 {
@@ -243,7 +259,7 @@ sub help {
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"
. "COMMANDS\n\n";
@@ -252,7 +268,7 @@ sub help {
}
print "\nTo view more information for commands run:\n"
. "snap <COMMAND> -h\n\n";
. "snap <COMMAND> -h\n";
}
1;

View File

@@ -1,10 +1,13 @@
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 \
$(DESTDIR)/usr/share/snap/Makefile.skel
install -v -m 644 Makefile.snaplinux \

View File

@@ -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 =
@@ -19,7 +75,7 @@ ARCHIVE := $(PWD)/SRC/$(shell ls SRC|egrep '(bz2|gz|tar|xz)$$'|tail -1)
TYPE := $(shell file -ib $(ARCHIVE)|cut -d';' -f1|tr -d '\n')
SRCDIR := $(shell tar -tf $(ARCHIVE)|head -1|sed 's/\/.*//')
PATCHDIR := $(PWD)/SRC/patches
VERSION := $(shell echo $(SRCDIR)|egrep -o '\-[0-9].*'|sed 's/^-//')$(SNAPVER)
VERSION := $(shell echo $(SRCDIR)|egrep -o '\-[0-9].*'|sed 's/^-//')-$(SNAPVER)
include /usr/share/snap/Makefile.snaplinux
@@ -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

View File

@@ -8,56 +8,107 @@
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
export SHELL := /bin/bash
PWD := $(shell pwd)
PACKAGE := $(shell echo $(PWD)|sed 's/.*\///')
SNAPDIR = $(PWD)/SNAP
ROOT = $(PWD)/ROOT
SNAP = $(PACKAGE)-$(VERSION).snap
SNAPINFO = $(SNAPDIR)/snapinfo
MANIFEST = $(SNAPDIR)/manifest
USHER = $(SNAPDIR)/usher
FILES = $(SNAPDIR)/files.tar.gz
# This will set PACKAGE to the name of the current working directory
# if the package itself has not provided a package name
# 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
ifeq ( $(SRCPKG), )
SRCPKG := $(PACKAGE)
ifndef PACKAGE
PACKAGE := $(shell echo $(PWD)|sed 's/.*\///')
endif
# The following values must be set in the Makefile for the package
# If VERSION is not set then we must fail
ifndef VERSION
$(error VERSION is not set)
endif
$(SNAP): $(SNAPINFO) $(FILES)
@if [ -f $(SNAP) ]; then \
rm -v $(SNAP); \
# This defines the name of the package file unless
# 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
# BRIEF is required.
ifndef BRIEF
$(error BRIEF is not set)
endif
$(PKGFILE): $(SNAPINFO) $(FILES)
@if [ -f $(PKGFILE) ]; then \
rm -v $(PKGFILE); \
fi
@ar cvr $(SNAP) $(SNAPINFO) $(MANIFEST); \
@ar cvr $(PKGFILE) $(SNAPINFO) $(MANIFEST); \
if [ -f $(USHER) ]; then \
chmod +x $(USHER); \
ar cvr $(SNAP) $(USHER); \
ar cvr $(PKGFILE) $(USHER); \
fi; \
ar cvr $(SNAP) $(FILES)
ar cvr $(PKGFILE) $(FILES)
@echo "Successfully built $(SNAP)"
@echo "Successfully built $(PKGFILE)"
$(SNAPINFO): $(MANIFEST)
@>$(SNAPINFO)
$(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)
@@ -99,27 +150,31 @@ $(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
if [ "$(PACKAGE)" != 'grub' ]; then
@find $(ROOT) -type f | while read -r file; do \
type=`file -i $$file|sed 's/.*: //'`; \
case $$type in \
*'/x-executable; charset=binary') \
strip --strip-unneeded $$file \
;; \
*'/x-object; charset=binary') \
strip --strip-unneeded $$file \
;; \
*'/x-sharedlib; charset=binary') \
strip --strip-unneeded $$file \
;; \
esac; \
done; \
fi
@find $(ROOT) -type f | while read -r file; do \
type=`file -i $$file|sed 's/.*: //'`; \
case $$type in \
*'/x-executable; charset=binary') \
echo "--strip-unneeded $$file"; \
strip --strip-unneeded $$file \
;; \
*'/x-object; charset=binary') \
echo "--strip-debug $$file"; \
strip --strip-debug $$file \
;; \
*'/x-sharedlib; charset=binary') \
echo "--strip-debug $$file"; \
strip --strip-debug $$file \
;; \
esac; \
done
@cd $(ROOT) && tar cvzf $(FILES) *

View File

@@ -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 ) );
}
@@ -255,7 +267,7 @@ sub depends {
} );
if ( ! $package ) {
push( @$failures, $depend );
push( @$failures, "$depend" );
next;
}
@@ -273,16 +285,96 @@ sub depends {
}
if ( @$failures ) {
print STDERR "Failed to resolve dependencies for"
. " $self->{'name'}!\n";
print STDERR "Failed to resolve dependencies\n";
Snap->error( -1, "depends(): dependencies failed: "
Snap->error( -1, "depends(): unresolved dependencies: "
. join( ",", @$failures ) );
}
$self->revdeps( $sources, $dependencies );
}
sub dump {
my $self = shift;
my $pid;
my $sel;
my $cnt;
my $stderr;
my $stat;
local $| = 1;
if ( $self->{'path'} =~ /^https*:\/\// ) {
( my $filename = $self->{'path'} ) =~ s/.*\///;
Snap->httpget( $self->{'path'}, Snap->PKGDIR
. "/$filename", 0644 );
$self->{'path'} = Snap->PKGDIR . "/$filename";
}
print "Dumping $self->{'name'}=$self->{'version'}\n";
print "\e[?25l\r";
eval {
my $target = Snap->TARGET ||
"$self->{'name'}-$self->{'version'}";
if ( ! -d $target ) {
mkdir( $target );
}
$pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR,
"/usr/bin/ar p $self->{'path'} files.tar.gz|"
. "tar --no-overwrite-dir --keep-directory-symlink"
. " -hzvxf - -C $target" );
} || Snap->error( int( $! ), "open3(): /usr/bin/ar: $!" );
close( CHLDIN );
$sel = IO::Select->new();
$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 ) ) {
my $line = <$fh>;
( my $file = $line ) =~ s/.*\/|\n$//;
chomp( $line );
chomp( $file );
if ( $file ) {
$cnt++;
print "\e[K$file\r";
}
}
elsif ( fileno( $fh ) == fileno( *CHLDERR ) ) {
$stderr .= <$fh>;
}
}
}
close( CHLDOUT );
close( CHLDERR );
waitpid( $pid, 0 );
$stat = $? >> 8;
if ( $stat ) {
Snap->error( $stat, "Failed dumping $self->{'name'}:"
. " $stderr\e[?25h" );
}
print "\e[K$cnt files extracted\e[?25h\n";
}
sub files {
my $self = shift;
my $opts = shift;
@@ -294,8 +386,13 @@ sub files {
my $stdout;
my $stderr;
my $stat;
my $pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR,
"/usr/bin/ar p $self->{'path'} manifest" );
my $pid;
eval {
$pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR,
"/usr/bin/ar p $self->{'path'} manifest" );
} || Snap->error( int( $! ), "open3(): /usr/bin/ar:"
. " $!" );
close( CHLDIN );
@@ -318,7 +415,12 @@ sub files {
next;
}
if ( $opts->{'quiet'} ) {
if ( $opts->{'quiet'} &&
$opts->{'verbose'} ) {
push( @{$self->{'files'}}, [
$sha, $perms, $file ] );
}
elsif ( $opts->{'quiet'} ) {
push( @{$self->{'files'}},
$file );
}
@@ -368,7 +470,13 @@ sub files {
$self->{'files'} = [];
}
push( @{$self->{'files'}}, $file );
if ( $opts->{'verbose'} ) {
push( @{$self->{'files'}}, [
$sha, $perms, $file ] );
}
else {
push( @{$self->{'files'}}, $file );
}
}
elsif ( $opts->{'verbose'} ) {
print "$sha\t$perms\t$file\n";
@@ -387,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;
@@ -402,7 +591,23 @@ sub install {
my $stat;
local $| = 1;
print "\e[?25lInstalling $self->{'name'}:\r";
####################################################
#
# 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'} ) {
Snap->error( -1, "install(): $self->{'path'}:"
. " No such file or directory" );
}
if ( $self->{'path'} =~ /^https*:\/\// ) {
( my $filename = $self->{'path'} ) =~ s/.*\///;
@@ -414,7 +619,7 @@ sub install {
}
if ( ! -d $pkgdir ) {
mkdir( $pkgdir, 0644 ) ||
mkdir( $pkgdir, 0755 ) ||
Snap->error( int( $! ), "mkdir(): $pkgdir: $!" );
}
@@ -443,13 +648,19 @@ sub install {
Snap->error( int( $! ), "rename(): $manifest: $!" );
}
print "Installing $self->{'name'}=$self->{'version'}\n";
$self->usher( 'preinst' );
print "\e[?25l\r";
eval {
my $target = Snap->TARGET || '/';
$pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR,
"/usr/bin/ar p $self->{'path'} files.tar.gz|"
. "tar --no-overwrite-dir -hzvxf - -C "
. Snap->TARGET );
. "tar --no-overwrite-dir --keep-directory-symlink"
. " -hzvxf - -C $target" );
} || Snap->error( int( $! ), "open3(): /usr/bin/ar: $!" );
close( CHLDIN );
@@ -481,8 +692,7 @@ sub install {
if ( $file ) {
$cnt++;
print "\e[KInstalling "
. "$self->{'name'}: $file\r";
print "\e[K$file\r";
}
}
elsif ( fileno( $fh ) == fileno( *CHLDERR ) ) {
@@ -502,6 +712,8 @@ sub install {
. " $stderr\e[?25h" );
}
print "\e[K$cnt files extracted\e[?25h\n";
if ( $oldpkg ) {
foreach ( @{$oldpkg->{'files'}} ) {
if ( -f Snap->TARGET . "/$_" ) {
@@ -548,16 +760,25 @@ sub install {
Snap->error( int( $! ), "unlink(): $manifest: $!" );
}
print "\e[KInstalling $self->{'name'}: DONE\e[?25h\n";
$self->infodir();
Snap->unlock();
print "Finished installing $self->{'name'}\n";
}
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" ) ||
@@ -577,6 +798,9 @@ sub installed {
return( 1 );
}
}
elsif ( -f $infofile ) {
return( 1 );
}
return( 0 );
}
@@ -585,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'} );
@@ -600,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";
}
@@ -630,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++;
}
}
@@ -652,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 {
@@ -741,7 +967,7 @@ sub usher {
my $stderr;
my $stat;
if ( ! -f $usher || $action eq 'preinst' ) {
if ( $action eq 'preinst' ) {
my $cnt = 0;
eval {
@@ -769,17 +995,16 @@ sub usher {
if ( fileno( $fh ) == fileno( *CHLDOUT ) ) {
my $line = <$fh>;
if ( ! $cnt && $line =~
/^no entry usher in archive$/ ) {
last;
}
print USHER $line;
$cnt++;
}
elsif ( fileno( $fh ) == fileno( *CHLDERR ) ) {
$stderr .= <$fh>;
if ( $stderr =~ /^no entry usher/ ) {
last;
}
}
}
}
@@ -798,24 +1023,73 @@ sub usher {
if ( ! $cnt && -f $usher ) {
unlink( $usher );
return;
}
}
####################################################
#
# 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;
}
eval {
$pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR,
"TARGET=" . Snap->TARGET . " $usher $action" );
} || Snap->error( int( $! ), "open3():"
. " $usher ($action): $!" );
if ( $pid = fork() ) {
waitpid( $pid, 0 );
$stat = $? >> 8;
}
elsif ( Snap->TARGET && installed( 'coreutils' ) &&
installed( 'dash' ) ) {
my $cmd;
$usher = substr( $usher, length( Snap->TARGET ) );
undef( $ENV{'TARGET'} );
close( CHLDIN );
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";
}
$sel = IO::Select->new();
$sel->add( *CHLDOUT, *CHLDERR );
$sel = IO::Select->new();
exec( $cmd );
}
else {
exec( "$usher $action" );
}
if ( $stat ) {
Snap->error( $stat, "usher(): Failed executing usher" );
}
}
############################################################
@@ -824,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...
#
############################################################
@@ -837,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;

View File

@@ -7,7 +7,7 @@ use Snap::Commands;
use Snap::Package;
use Snap::Sources;
use Fcntl;
use Fcntl qw( :flock );
use IPC::Open3;
use IO::Socket::INET;
use Digest::SHA qw( sha256_hex );
@@ -23,9 +23,12 @@ our @EXPORT = qw(
human
list
listfiles
virtfs
readconf
refresh
setup
sha
sha256
target
termsize
vercmp
@@ -86,7 +89,7 @@ use constant VERFILE => eval {
}
};
use constant {
VERSION => '0.3',
VERSION => '0.12',
SNAPDIR => TARGET . '/var/lib/snap',
PKGDIR => TARGET . '/var/lib/snap/packages',
INSTDIR => TARGET . '/var/lib/snap/installed',
@@ -102,6 +105,7 @@ use constant SNAPVER => eval {
return( $version );
};
use constant LOCKFILE => TARGET . '/.snap';
############################################################
#
@@ -118,6 +122,10 @@ $0 =~ s/.*\///;
############################################################
$SIG{INT} = sub{
if ( TARGET ) {
virtfs( 'umount' );
}
print "\e[?25h\n";
exit( -1 );
@@ -125,7 +133,7 @@ $SIG{INT} = sub{
############################################################
#
# Export TARGET to the environment
# Export TARGET to the environment for usher
#
############################################################
@@ -165,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': ";
@@ -195,6 +203,8 @@ sub error {
chomp( $errstr );
print "\e[?25h\n";
print STDERR ( caller() )[1] .":\n $errstr at line "
. ( caller() )[2] . "\n";
@@ -212,6 +222,8 @@ sub error {
print "\n";
if ( $status ) {
virtfs( 'umount' );
exit( $status );
}
}
@@ -284,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;
@@ -305,7 +319,7 @@ sub httpget {
while ( <$sock> ) {
if ( $dest ) {
$bytes = ( stat( $dest ) )[7] || 0;
$bytes += length( $_ );
}
if ( ! $httpget{'dflag'} ) {
@@ -356,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 );
}
@@ -404,7 +419,66 @@ sub human {
return( $human );
}
sub ismountpoint {
my $dir = shift;
my $statA;
my $statB;
if ( ! -d $dir ) {
return( 0 );
}
$statA = ( stat( $dir ) )[0];
$statB = ( stat( "$dir/.." ) )[0];
if ( $statA == $statB ) {
return( 0 );
}
else {
return( 1 );
}
}
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 {
my $listpackages = shift;
my $packages = {};
my $package = {};
@@ -412,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;
}
@@ -470,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;
@@ -486,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 ( <FILE> ) {
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;
@@ -515,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 );
}
@@ -567,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: $!" );
}
@@ -621,6 +710,15 @@ sub setup {
}
}
sub sha {
my $file = shift;
my $digest = eval {
Digest::SHA->new( 1 )->addfile( $file );
} || Snap->error( -1, "sha(): $file: $!\n" );
return( $digest->hexdigest );
}
### sha256() ###############################################
#
# This sub returns a hex sha256 hash of a supplied file
@@ -638,24 +736,61 @@ sub sha256 {
}
sub termsize {
require 'sys/ioctl.ph';
my $data;
my $row;
my $col;
my $row = 24;
my $col = 80;
my $sel = IO::Select->new();
my $stdout;
my $stderr;
my $stat;
my $pid;
open( TTY, "+</dev/tty" ) || Snap->error( 0, "No tty: $!" );
eval {
$pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR,
"stty size -F /dev/tty" );
} || return( { row => $row, col => $col } );
if ( ! ioctl( TTY, &TIOCGWINSZ, $data='' ) ) {
Snap->error( 0, "Failed to determine window size" );
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( TTY );
close( CHLDOUT );
close( CHLDERR );
( $row, $col ) = unpack( 'S4', $data );
waitpid( $pid, 0 );
$stat = $? >> 8;
if ( $stdout =~ /(\d+)\s+(\d+)/ ) {
$row = $1;
$col = $2;
}
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
@@ -732,4 +867,121 @@ 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 = {
dev => {
fs => 'devtmpfs',
dev => 'none',
dir => TARGET . '/dev'
},
proc => {
fs => 'proc',
dev => 'none',
dir => TARGET . '/proc'
},
sys => {
fs => 'sysfs',
dev => 'none',
dir => TARGET .'/sys'
}
};
if ( $> || ! TARGET ) {
return;
}
foreach my $fs ( sort( keys( %$virtfs ) ) ) {
my $sel;
my $cmd;
my $stdout = '';
my $stderr = '';
my $stat = 0;
my $pid;
if ( ! -d $virtfs->{$fs}{'dir'} ) {
next;
}
if ( $command eq 'mount' ) {
if ( ismountpoint( $virtfs->{$fs}{'dir'} ) ) {
next;
}
$cmd = "mount -t $virtfs->{$fs}{'fs'}"
. " $virtfs->{$fs}{'dev'}"
. " $virtfs->{$fs}{'dir'}";
}
elsif ( $command eq 'umount' ) {
if ( ! ismountpoint( $virtfs->{$fs}{'dir'} ) ) {
next;
}
$cmd = "umount $virtfs->{$fs}{'dir'}";
}
else {
Snap->error( -1, "virtfs(): $command:"
. " not a valid command" );
}
eval {
$pid = open3( \*CHLDIN, \*CHLDOUT, \*CHLDERR, $cmd );
} || Snap->error( int( $! ), "open3(): $cmd: $!" );
close( CHLDIN );
$sel = IO::Select->new();
$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 ( $stat ) {
Snap->error( $stat, "Failed $command for"
. " $virtfs->{$fs}{'dir'}: $stderr" );
}
}
foreach my $fs ( sort( keys( %$virtfs ) ) ) {
if ( ! ismountpoint( $virtfs->{$fs}{'dir'} ) ) {
return( 0 );
}
}
return( 1 );
}
1;

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,16 +6,7 @@ use warnings;
use Snap;
use Data::Dumper;
############################################################
#
# setup() will give the user the option to create the files
# and directories needed for snap to function
#
############################################################
setup();
my $command = shift( @ARGV );
my $command = shift( @ARGV ) || '';
my $conf = readconf();
my $commands = Snap::Commands->new();
my $sources = Snap::Sources->new( $conf->{'sources'} );
@@ -23,9 +14,15 @@ my $sources = Snap::Sources->new( $conf->{'sources'} );
if ( $ARGV[0] && $ARGV[0] eq '-h' ) {
$commands->commandhelp( $command );
}
elsif ( $command eq 'genpkg' ) {
elsif ( $command eq 'dump' ) {
print "\n";
foreach my $arg ( @ARGV ) {
genpkg( $arg );
my $package = Snap::Package->new( $arg );
$package->dump();
print "\n";
}
}
elsif ( $command eq 'files' ) {
@@ -51,29 +48,41 @@ 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 ) {
genpkg( $arg );
}
}
elsif ( $command eq 'help' ) {
$commands->help();
}
elsif ( $command eq 'info' ) {
my $cnt = 0;
print "\n";
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' ) {
@@ -102,6 +111,9 @@ elsif ( $command eq 'install' ) {
my $string = "@ARGV";
my $packages = [];
my $bytes = 0;
my $virtfs = 0;
setup();
foreach my $attrib ( @attribs ) {
if ( $string =~ /$attrib\s*:\s*(\S+)/ ) {
@@ -111,8 +123,6 @@ elsif ( $command eq 'install' ) {
}
}
print "\n";
$sources->readpkgs();
####################################################
@@ -138,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;
@@ -150,7 +160,7 @@ elsif ( $command eq 'install' ) {
}
if ( ! $package ) {
Snap->error( -1, "$arg: No such package found" );
exit( -1 );
}
if ( ! $opts->{'nodeps'} ) {
@@ -291,36 +301,77 @@ elsif ( $command eq 'install' ) {
}
}
print "\n\nInstall will require " . human( $bytes )
. ". Continue? (y/n): ";
if ( $bytes < 0 ) {
print "\n\nInstall will recover " . human( -1 * $bytes )
. ". Continue? (y/n): ";
}
else {
print "\n\nInstall will require " . human( $bytes )
. ". Continue? (y/n): ";
}
chkyes();
print "\n";
if ( ! $opts->{'yes'} ) {
chkyes();
}
foreach my $package ( @$packages ) {
if ( ! $virtfs ) {
$virtfs = virtfs( 'mount' );
}
print "\n";
$package->install( $sources );
}
print "\n";
if ( $virtfs ) {
virtfs( 'umount' );
}
}
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' ) {
print "\n";
setup();
$sources->refresh();
print "\n";
exit;
foreach my $source ( @{$conf->{'sources'}} ) {
@@ -331,6 +382,102 @@ elsif ( $command eq 'refresh' ) {
print "\n";
}
}
elsif ( $command eq 'reinstall' ) {
my $opts = {
quiet => 1,
yes => eval {
for ( my $i = 0; $i <= $#ARGV; $i++ ) {
if ( $ARGV[$i] eq '-y' ) {
splice( @ARGV, $i, 1 );
return( 1 );
}
}
}
};
my $termsize = Snap->termsize();
my $packages = [];
my $virtfs = 0;
my $cnt = 0;
setup();
$sources->readpkgs();
foreach my $pkgname ( @ARGV ) {
my $package;
if ( -f $pkgname ) {
$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'},
version => $package->{'version'},
quiet => 1
} );
}
if ( $package->{'path'} =~ /https*:\/\// ) {
( my $filename = $package->{'path'} ) =~ s/.*\///;
if ( ! -f Snap->PKGDIR . "/$filename" ) {
Snap->httpget( $package->{'path'},
Snap->PKGDIR . "/$filename", 0644 );
}
$package->{'path'} = Snap->PKGDIR . "/$filename";
}
$package->files( $opts );
push( @$packages, $package );
}
foreach my $package ( sort { $a->{'name'} cmp $b->{'name'} }
( @$packages ) ) {
if ( ! $cnt ) {
print "The following packages will be"
. " reinstalled:\n ";
$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): ";
if ( ! $opts->{'yes'} ) {
chkyes();
}
foreach my $package ( @$packages ) {
if ( ! $virtfs ) {
$virtfs = virtfs( 'mount' );
}
print "\n";
$package->install();
}
virtfs( 'umount' );
}
elsif ( $command eq 'remove' ) {
my $opts = {
nodeps => eval {
@@ -359,8 +506,6 @@ elsif ( $command eq 'remove' ) {
my $cnt = 0;
my $termsize = Snap->termsize();
print "\n";
$sources->readpkgs();
foreach my $arg ( split( /\s/, $string ) ) {
@@ -391,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(
@@ -412,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 ) {
@@ -442,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 );
@@ -488,62 +643,85 @@ 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 );
}
print "\n";
}
elsif ( $command eq 'setup' ) {
elsif ( $command eq 'source' ) {
my $opts = {
repo => 'core',
latest => eval {
for ( my $i = 0; $i <= $#ARGV; $i++ ) {
if ( $ARGV[$i] eq '-l' ) {
splice( @ARGV, $i, 1 );
return( 1 );
}
}
},
quiet => 1
};
my $packages;
print "\n";
if ( ! Snap->TARGET ) {
Snap->error( -1, 'A target must be specified with -t' );
}
$sources->readpkgs();
$packages = $sources->search( $opts );
for ( my $i = 0; $i <= $#$packages; $i++ ) {
if ( $packages->[$i]{'name'} eq 'snap-base' ) {
unshift( @$packages, $packages->[$i] );
splice( @$packages, $i+1, 1 );
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 );
}
}
foreach my $package ( @$packages ) {
$package->install();
$package->source();
}
}
elsif ( $command eq 'upgrade' ) {
print "Not yet implemented\n";
print "\n";
exit( -1 );
}
elsif ( $command eq 'verify' ) {
print "Not yet implemented\n";
exit( -1 );
foreach my $arg ( @ARGV ) {
my $package = Snap::Package->new( $arg );
print Dumper( $package );
}
}
elsif ( $command eq 'version' ) {
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 );
}

162
SRC/snap/snapinstall Normal file
View File

@@ -0,0 +1,162 @@
#!/usr/bin/perl
use strict;
use warnings;
use Snap;
use Data::Dumper;
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
};
my $corepkgs;
my $packages;
my $virtfs = 0;
my $prepkgs = {};
my @prelist = qw(
);
my @packages = ();
if ( ! Snap->TARGET ) {
Snap->error( -1, 'A target must be specified with -t' );
}
$sources->readpkgs();
foreach my $pkgname ( @{$conf->{'templates'}{'core'}} ) {
my $package = $sources->search( { name => $pkgname, quiet => 1 } );
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 {
Snap->error( -1, "$package->{'name'}:"
. " Unable to determine package path" );
}
}
push( @packages, $package );
}
foreach my $package ( @packages ) {
$package->files( $opts );
print "\n";
$package->install();
}
if ( ! @packages ) {
print "Nothing to do\n";
}
else {
print "Setting root password\n";
if ( $> ) {
exec( "fakeroot fakechroot /usr/sbin/chroot "
. Snap->TARGET . " passwd root" );
}
else {
exec ( "chroot " . Snap->TARGET . " passwd root" );
}
}
exit;
#$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";