Initial commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
vendor_perl
|
||||
data/config.json
|
||||
94
.perlcriticrc
Normal file
94
.perlcriticrc
Normal file
@@ -0,0 +1,94 @@
|
||||
#!/usr/bin/env perlcritic
|
||||
severity = 5
|
||||
verbose = 8
|
||||
|
||||
# minorify some of warnings that are not really critical
|
||||
[-InputOutput::RequireCheckedClose]
|
||||
# What can we handle in case of error?
|
||||
|
||||
#[-Modules::ProhibitExcessMainComplexity]
|
||||
# Noone cares
|
||||
|
||||
[-Subroutines::ProhibitExcessComplexity]
|
||||
# Noone cares
|
||||
|
||||
#[-Subroutines::ProhibitExplicitReturnUndef]
|
||||
# But it's very handy sometimes!
|
||||
|
||||
[-ValuesAndExpressions::ProhibitMagicNumbers]
|
||||
# this policy makes too much false positives
|
||||
|
||||
#[-RegularExpressions::RequireLineBoundaryMatching]
|
||||
# We use /m as needed
|
||||
|
||||
#[-RegularExpressions::RequireExtendedFormatting]
|
||||
# We do not use extended formatting of regex, they still not THAT complex
|
||||
|
||||
#[-RegularExpressions::RequireDotMatchAnything]
|
||||
# huh?
|
||||
|
||||
[-RegularExpressions::ProhibitEscapedMetacharacters]
|
||||
# Looks like it pointless. How can i match simple dot without putting \. in regex? fuck off, man
|
||||
|
||||
#[-ControlStructures::ProhibitCascadingIfElse]
|
||||
# I like long if..else chains
|
||||
|
||||
[-ControlStructures::ProhibitPostfixControls]
|
||||
# In short lines we can afford ourselves to use postfix controls
|
||||
# but ofcorse we should avoid such constructions in long lines.
|
||||
|
||||
[-Subroutines::ProhibitSubroutinePrototypes]
|
||||
# Contrary to Perl::Critic we consider prototypes as useful, even if
|
||||
# the compile-time checks of Perl are not perfect, Perl may give some
|
||||
# hints.
|
||||
|
||||
[-CodeLayout::RequireTidyCode]
|
||||
# Impossible to complete, because of on higher linting levels "## no critic..."
|
||||
# require be per-case on same line where critique is, but tidy align them
|
||||
# one line down.
|
||||
|
||||
[-CodeLayout::ProhibitParensWithBuiltins]
|
||||
# duh... in some cases it reduces readbility
|
||||
|
||||
[-ValuesAndExpressions::ProhibitEmptyQuotes]
|
||||
# cause we consider following correct and useful: my $var = '';
|
||||
# the recomended use of q{} looks too complex: my $var = q{};
|
||||
|
||||
[-ValuesAndExpressions::ProhibitNoisyQuotes]
|
||||
# Other people, other opinions: "," is better readable than qw(,)
|
||||
|
||||
#[-BuiltinFunctions::ProhibitSleepViaSelect]
|
||||
# We do not wish to use too much external modules.
|
||||
# select undef, undef, undef, 0.25; # actually is okay if you add comment that
|
||||
# it is sleep for 0.25 seconds
|
||||
|
||||
[-NamingConventions::Capitalization]
|
||||
# duh...
|
||||
# Noone care, really
|
||||
|
||||
[-ControlStructures::ProhibitUnlessBlocks]
|
||||
# They should not be too complex - only one condition should be checked,
|
||||
# that's all
|
||||
|
||||
#[-Miscellanea::ProhibitTies]
|
||||
# Just allow it. It's very handy stuff and extremely simple and safe enugh to use.
|
||||
|
||||
[-ValuesAndExpressions::RequireNumberSeparators]
|
||||
# Not really
|
||||
|
||||
#[-InputOutput::RequireBracedFileHandleWithPrint]
|
||||
# We prefer not to use braced file handles
|
||||
|
||||
#[-Documentation::PodSpelling]
|
||||
# It doesn't help, but emits annoying errors
|
||||
|
||||
#[Documentation::RequirePodSections]
|
||||
# Considering this as "soft" requirement. For modules that is (or will be)
|
||||
# stand-alone libs well formed documentation is highly desired.
|
||||
#lib_sections = NAME | VERSION | DESCRIPTION | AUTHOR | LICENSE AND COPYRIGHT
|
||||
|
||||
[-InputOutput::RequireBriefOpen]
|
||||
# Yes, i do!
|
||||
|
||||
[-ValuesAndExpressions::ProhibitLongChainsOfMethodCalls]
|
||||
# But i do really want to use them in JSON::XS declaration!
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Sergei Fedosoff <eleksir@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
154
README.md
Normal file
154
README.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# Slackmetarep - Slackware repository metadata generator
|
||||
|
||||
## About
|
||||
|
||||
Slackware repository metadata generator and upload server.
|
||||
|
||||
## What for?
|
||||
|
||||
For receiving package uploads and creating metadata for slackware package repositories.
|
||||
|
||||
Main idea is to use it in automated CI process.
|
||||
|
||||
## What this application is not for?
|
||||
|
||||
It is not designed for large scale repositories or for use as a public service.
|
||||
|
||||
## How it works?
|
||||
|
||||
Upload file to repository via PUT request:
|
||||
|
||||
```bash
|
||||
curl -X PUT --data-binary "@/bin/bash" -H 'auth: welcometothejungle' http://reposerver.tld/api/upload/repository/file.ext
|
||||
```
|
||||
|
||||
Where **repository** is same that set in config.json and **file.ext** is package or piece of metadata
|
||||
|
||||
When all chunks of metadata and package are uploaded, you may issue metagen command:
|
||||
|
||||
```bash
|
||||
curl -H 'repo: repository' 'http://reposerver.tld/api/metagen'
|
||||
```
|
||||
|
||||
### What metadata?
|
||||
|
||||
As an example for building this application data format in AlienBob repository is taken. There is some different files
|
||||
that contain pieces of information for generating metadata comptible with one used for Slackware-14.2 repositories.
|
||||
|
||||
More detailed information in [docs/metadata_en.md](docs/metadata_en.md)
|
||||
|
||||
So this tool needs these metadata chunks to properly write metadata:
|
||||
|
||||
* packagename-version-arch-suffix.lst
|
||||
* packagename-version-arch-suffix.meta
|
||||
* packagename-version-arch-suffix.tgz.md5
|
||||
* packagename-version-arch-suffix.txt
|
||||
|
||||
Additional JSON-formatted metadata if required for buildinfo module to work. An example of it:
|
||||
|
||||
```json
|
||||
{
|
||||
"dmenu" : {
|
||||
"SRC" : [
|
||||
"dmenu-4.8.tar.gz"
|
||||
]
|
||||
},
|
||||
"docker" : {
|
||||
"DEPS" : [
|
||||
"containerd",
|
||||
"docker-proxy",
|
||||
"tini",
|
||||
"google-go-lang"
|
||||
],
|
||||
"GROUP" : {
|
||||
"docker" : "281"
|
||||
},
|
||||
"SRC" : [
|
||||
"docker-ce-19.03.13.tar.gz"
|
||||
],
|
||||
"USER" : {
|
||||
"docker" : {
|
||||
"GROUP" : "docker",
|
||||
"HOME" : "/var/lib/docker",
|
||||
"SHELL" : "/bin/false",
|
||||
"UID" : "281"
|
||||
}
|
||||
}
|
||||
},
|
||||
"perf" : {
|
||||
"DEPS" : [
|
||||
"libunwind",
|
||||
"kernel-headers",
|
||||
"kernel-source"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
But this data intended to help in package build script that prepares build environment, runs SlackBuilds, upload
|
||||
files to repo and kicks metadata generation process.
|
||||
|
||||
All metadata required and generated by this application very-very close to one found in AlienBob's
|
||||
[repositories](http://www.slackware.com/~alien/slackbuilds/), except no changelogs and rss are generated.
|
||||
|
||||
## Installation
|
||||
|
||||
In order to run this application, you need to "bootstrap" it - download and build
|
||||
all required dependencies and libraries.
|
||||
|
||||
You'll need "Development Tools" or similar group of packages, perl, perl-devel,
|
||||
perl-local-lib, perl-app-cpanm, zlib-devel, openssl-devel, libdb4-devel (Berkeley DB devel), make.
|
||||
|
||||
After installng required dependencies it is possible to run:
|
||||
|
||||
```bash
|
||||
bash bootstrap.sh
|
||||
```
|
||||
|
||||
and all libraries should be downloaded, built, tested and installed.
|
||||
|
||||
## How to run this?
|
||||
|
||||
Via [uWSGI](https://github.com/unbit/uwsgi).
|
||||
|
||||
```bash
|
||||
#!/bin/ash
|
||||
|
||||
exec 2>&1
|
||||
|
||||
LOGDIR=/var/log/uwsgi
|
||||
PIDDIR=/var/run/uwsgi
|
||||
WORKDIR=/var/www/slackmetarep
|
||||
|
||||
mkdir -p $LOGDIR
|
||||
chown -R apache:apache $LOGDIR
|
||||
mkdir -p $PIDDIR
|
||||
|
||||
cd $WORKDIR
|
||||
|
||||
# for 100% sure
|
||||
export PERL5LIB="${WORKDIR}/vendor_perl"
|
||||
export PERL_LIB="$PERL5LIB"
|
||||
|
||||
exec sudo -u apache -g apache /usr/bin/uwsgi \
|
||||
--yaml ${WORKDIR}/slackmetarep.yaml \
|
||||
--pidfile ${PIDDIR}/slackmetarep.pid \
|
||||
--perl-local-lib ${PERL5LIB}
|
||||
|
||||
```
|
||||
|
||||
At least i use uwsgi for this. Starman suits well too and should work without any problems. You can also try
|
||||
[Nginx UNIT](https://unit.nginx.org/), but it was totally not tested.
|
||||
|
||||
## How to contribute?
|
||||
|
||||
Got something about this project? Make PR.
|
||||
|
||||
## Who should i thank?
|
||||
|
||||
Slackware mainatiners for their continous labour. Notably [AlienBob](https://docs.slackware.com/wiki:user:alienbob) and
|
||||
SBo team.
|
||||
|
||||
## What is missing here?
|
||||
|
||||
At least proper documentaion of metadata format generated by this particular application.
|
||||
86
Slackmetarep/Buildinfo.pm
Normal file
86
Slackmetarep/Buildinfo.pm
Normal file
@@ -0,0 +1,86 @@
|
||||
package Slackmetarep::Buildinfo;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use vars qw/$VERSION/;
|
||||
use English qw( -no_match_vars );
|
||||
use Carp;
|
||||
|
||||
use JSON::XS;
|
||||
use Slackmetarep::Conf qw(loadConf);
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT_OK = qw(buildinfo);
|
||||
|
||||
$VERSION = '1.0';
|
||||
|
||||
my $c = loadConf();
|
||||
|
||||
sub buildinfo ($) {
|
||||
my $repo = shift;
|
||||
my ($status, $content, $msg) = ('400', 'text/plain', "Bad Request?\n");
|
||||
|
||||
return ($status, $content, $msg) unless ($repo =~ /\//xmsg);
|
||||
|
||||
my ($config, $package) = split(/\//xms, $repo);
|
||||
|
||||
unless (defined($c->{buildinfo}->{$config})) {
|
||||
$msg = "Config repo $config is not defined in config.\n";
|
||||
return ($status, $content, $msg);
|
||||
}
|
||||
|
||||
open (my $jhandle, '<', $c->{buildinfo}->{$config}) or do {
|
||||
$status = '500';
|
||||
$msg = "Unable to open $c->{buildinfo}->{$config}; $OS_ERROR\n";
|
||||
carp '[FATA] ' . $msg;
|
||||
return ($status, $content, $msg);
|
||||
};
|
||||
|
||||
my $len = (stat($c->{buildinfo}->{$config}))[7];
|
||||
my $json;
|
||||
my $readlen = read ($jhandle, $json, $len);
|
||||
close $jhandle; ## no critic (InputOutput::RequireCheckedSyscalls
|
||||
|
||||
unless (defined($readlen)) {
|
||||
$status = '500';
|
||||
$msg = "Unable to read $c->{buildinfo}->{$config}: $OS_ERROR";
|
||||
carp '[FATA] ' . $msg;
|
||||
return ($status, $content, $msg);
|
||||
}
|
||||
|
||||
if ($len != $readlen) {
|
||||
$status = '500';
|
||||
$msg = "Size of $c->{buildinfo}->{$config} $len bytes but actually read $readlen bytes";
|
||||
carp '[FATA] ' . $msg;
|
||||
return ('500', $content, "Unable to read $c->{buildinfo}->{$config}\n");
|
||||
}
|
||||
|
||||
my $j = eval { decode_json($json) } or do {
|
||||
$status = '500';
|
||||
$msg = "Error during decoding $c->{buildinfo}->{$config}; $EVAL_ERROR\n";
|
||||
carp '[FATA] ' . $msg;
|
||||
return ($status, $content, $msg);
|
||||
};
|
||||
|
||||
unless (defined($j->{$package})) {
|
||||
$msg = "$package is not defined in config for $config.\n";
|
||||
carp '[ERRO] ' . $msg;
|
||||
return ($status, $content, $msg);
|
||||
}
|
||||
|
||||
$json = JSON::XS->new->pretty->canonical->indent(1)->encode($j->{$package}) or do {
|
||||
$status = '500';
|
||||
$msg = "Unable to encode json.\n";
|
||||
carp '[ERRO] ' . $msg;
|
||||
return ($status, $content, $msg);
|
||||
};
|
||||
|
||||
$status = '200';
|
||||
$content = 'application/json';
|
||||
$msg = $json;
|
||||
return ($status, $content, $msg);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set ft=perl noet ai ts=4 sw=4 sts=4:
|
||||
43
Slackmetarep/Conf.pm
Normal file
43
Slackmetarep/Conf.pm
Normal file
@@ -0,0 +1,43 @@
|
||||
package Slackmetarep::Conf;
|
||||
# loads config
|
||||
|
||||
use 5.018;
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
use open qw(:std :utf8);
|
||||
use English qw( -no_match_vars );
|
||||
|
||||
use vars qw/$VERSION/;
|
||||
use JSON::XS;
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT_OK = qw(loadConf);
|
||||
|
||||
$VERSION = '1.0';
|
||||
|
||||
sub loadConf {
|
||||
my $c = 'data/config.json';
|
||||
open my $CH, '<', $c || die "[FATA] No conf at $c: $OS_ERROR\n";
|
||||
my $len = (stat ($c)) [7];
|
||||
my $json;
|
||||
my $readlen = read $CH, $json, $len;
|
||||
|
||||
unless ($readlen) {
|
||||
close $CH; ## no critic (InputOutput::RequireCheckedSyscalls
|
||||
die "[FATA] Unable to read $c: $OS_ERROR\n";
|
||||
}
|
||||
|
||||
if ($readlen != $len) {
|
||||
close $CH; ## no critic (InputOutput::RequireCheckedSyscalls
|
||||
die "[FATA] File $c is $len bytes on disk, but we read only $readlen bytes\n";
|
||||
}
|
||||
|
||||
close $CH; ## no critic (InputOutput::RequireCheckedSyscalls
|
||||
my $j = JSON::XS->new->utf8->relaxed;
|
||||
return $j->decode ($json);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set ft=perl noet ai ts=4 sw=4 sts=4:
|
||||
387
Slackmetarep/Metagen.pm
Normal file
387
Slackmetarep/Metagen.pm
Normal file
@@ -0,0 +1,387 @@
|
||||
# Most of this data is generated during package build process and being uploaded
|
||||
# to pool alongside with packages themselves. So we can easily and fast regen meta.
|
||||
|
||||
# Assume that whole operation takes resonable amount of time to perform it syncronously
|
||||
|
||||
# metadata consists of
|
||||
# * CHECKSUMS.md5 or CHECKSUMS.md5.gz - checksum of each file in repo
|
||||
# * ChangeLog.txt - optional, contains history of changes, this script does not
|
||||
# handle it
|
||||
# * FILELIST.TXT - whole list of files that are part of repostory data or
|
||||
# metadata
|
||||
# * PACKAGES.TXT - packages description with metainfo such as relative path in
|
||||
# repo, compressed size and uncompressed size
|
||||
# * MANIFEST.bz2 - list of files in each package
|
||||
|
||||
# TODO: make metadata in atomic way
|
||||
# TODO: validate metadata
|
||||
|
||||
package Slackmetarep::Metagen;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use utf8;
|
||||
use open qw(:std :utf8);
|
||||
use vars qw/$VERSION/;
|
||||
use English qw( -no_match_vars );
|
||||
|
||||
use Carp;
|
||||
use Fcntl;
|
||||
use Compress::Raw::Bzip2 qw(BZ_RUN_OK BZ_STREAM_END);
|
||||
use Compress::Raw::Zlib;
|
||||
use POSIX qw(strftime);
|
||||
|
||||
use Slackmetarep::Conf qw(loadConf);
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT_OK = qw(metagen);
|
||||
|
||||
$VERSION = '1.0';
|
||||
|
||||
sub metagen($);
|
||||
sub __pdate; # generates current date in pretty format
|
||||
sub __trim($);
|
||||
sub __readfile($);
|
||||
sub __dirlist($);
|
||||
sub __writefile(@);
|
||||
sub __bzdata($);
|
||||
sub __gzdata($);
|
||||
|
||||
sub metagen ($) {
|
||||
my $dir = shift;
|
||||
my $c = loadConf();
|
||||
$dir = $c->{metagen}->{$dir};
|
||||
|
||||
unless (defined $dir || ($dir eq '')) {
|
||||
return ('400', 'text/plain', "No such repository\n");
|
||||
}
|
||||
|
||||
my $dirlist = __dirlist ($dir);
|
||||
return ('500', 'text/plain', $dirlist->{error}) if (defined $dirlist->{error});
|
||||
my @filelist = @{$dirlist->{dir}};
|
||||
$dirlist = undef;
|
||||
|
||||
# manifest
|
||||
my $buf = '';
|
||||
|
||||
foreach my $filename (@filelist) {
|
||||
if ($filename =~ /\.lst/xmsg) {
|
||||
my $file = __readfile("$dir/$filename");
|
||||
return ('500', 'text/plain', $file->{error}) if (defined $file->{'error'});
|
||||
$buf .= __trim $file->{data};
|
||||
$buf .= "\n\n\n";
|
||||
$file->{data} = ''; $file = undef;
|
||||
}
|
||||
}
|
||||
|
||||
my $bzdata = __bzdata (\$buf);
|
||||
return ('500', 'text/plain', $bzdata->{error}) if (defined $bzdata->{error});
|
||||
|
||||
my $manifest = __writefile ("$dir/MANIFEST.bz2", \$bzdata->{data});
|
||||
return ('500', 'text/plain', $manifest->{error}) if (defined $manifest->{error});
|
||||
|
||||
$bzdata->{data} = ''; $bzdata = undef;
|
||||
|
||||
# checksums
|
||||
$buf = << 'MSG';
|
||||
These are the MD5 message digests for the files in this directory.
|
||||
If you want to test your files, use 'md5sum' and compare the values to
|
||||
the ones listed here.
|
||||
|
||||
To test all these files, use this command:
|
||||
|
||||
tail +13 CHECKSUMS.md5 | md5sum --check | less
|
||||
|
||||
'md5sum' can be found in the GNU coreutils package on ftp.gnu.org in
|
||||
/pub/gnu, or at any GNU mirror site.
|
||||
|
||||
MD5 message digest Filename
|
||||
MSG
|
||||
|
||||
foreach my $filename (@filelist) {
|
||||
next if ($filename =~ /CHECKSUMS\.md5$/xmsg);
|
||||
next if ($filename =~ /CHECKSUMS.md5.gz$/xmsg);
|
||||
|
||||
if ($filename =~ /\.md5/xmsg) {
|
||||
my $file = __readfile("$dir/$filename");
|
||||
return ('500', 'text/plain', $file->{error}) if (defined $file->{'error'});
|
||||
$buf .= $file->{data};
|
||||
$file->{data} = ''; $file = undef;
|
||||
}
|
||||
}
|
||||
|
||||
my $checksum = __writefile ("$dir/CHECKSUMS.md5", \$buf);
|
||||
return ('500', 'text/plain', $checksum->{error}) if (defined $checksum->{error});
|
||||
|
||||
my $gzipchecksum = __gzdata(\$buf);
|
||||
return ('500', 'text/plain', $gzipchecksum->{error}) if (defined $gzipchecksum->{error});
|
||||
$buf = '';
|
||||
|
||||
my $checksumgz = __writefile ("$dir/CHECKSUMS.md5.gz", \$gzipchecksum->{data});
|
||||
return ('500', 'text/plain', $checksumgz->{error}) if (defined $checksumgz->{error});
|
||||
$gzipchecksum->{data} = ''; $gzipchecksum = undef;
|
||||
|
||||
# packages
|
||||
$buf = sprintf "PACKAGES.TXT; %s\n\n\n", __pdate;
|
||||
|
||||
foreach my $filename (@filelist) {
|
||||
if ($filename =~ /\.meta/xmsg) {
|
||||
my $file = __readfile("$dir/$filename");
|
||||
return ('500', 'text/plain', $file->{error}) if (defined $file->{'error'});
|
||||
$buf .= __trim ($file->{data});
|
||||
$buf .= "\n\n";
|
||||
$file->{data} = ''; $file = undef;
|
||||
}
|
||||
}
|
||||
|
||||
my $packages = __writefile ("$dir/PACKAGES.TXT", \$buf);
|
||||
return ('500', 'text/plain', $packages->{error}) if (defined $packages->{error});
|
||||
|
||||
my $gzippackages = __gzdata(\$buf);
|
||||
return ('500', 'text/plain', $gzippackages->{error}) if (defined $gzippackages->{error});
|
||||
$buf = '';
|
||||
|
||||
my $packagesgz = __writefile ("$dir/PACKAGES.TXT.gz", \$gzippackages->{data});
|
||||
return ('500', 'text/plain', $packagesgz->{error}) if (defined $packagesgz->{error});
|
||||
$gzippackages->{data} = ''; $gzippackages = undef;
|
||||
|
||||
# filelist
|
||||
$buf = __pdate;
|
||||
$buf .= "\n\n";
|
||||
$buf .= << 'BUFFER';
|
||||
Here is the file list for this directory,
|
||||
maintained by eleksir <eleksir@gmail.com> .
|
||||
If you are using a mirror site and find missing or extra files
|
||||
in the subdirectories, please have the archive administrator
|
||||
refresh the mirror.
|
||||
|
||||
BUFFER
|
||||
|
||||
# dir listing is not actual, so we need to re-read it
|
||||
$#filelist = -1;
|
||||
$dirlist = __dirlist ($dir);
|
||||
return ('500', 'text/plain', $dirlist->{error}) if (defined $dirlist->{error});
|
||||
@filelist = @{$dirlist->{dir}};
|
||||
$dirlist = undef;
|
||||
|
||||
while (my $file = shift (@filelist)) {
|
||||
my $filename = sprintf ('%s/%s', $dir, $file);
|
||||
my @stat = stat $filename;
|
||||
my @date = localtime ($stat[10]);
|
||||
|
||||
$buf .= sprintf (
|
||||
"-rw-r--r-- %d root root % 8d %04d-%02d-%02d %02d:%02d ./%s\n",
|
||||
$stat[3],
|
||||
$stat[7],
|
||||
$date[5] + 1900,
|
||||
$date[4],
|
||||
$date[3],
|
||||
$date[2],
|
||||
$date[1],
|
||||
$file
|
||||
);
|
||||
}
|
||||
|
||||
$#filelist = -1;
|
||||
my $filelist = __writefile ("$dir/FILELIST.TXT", \$buf);
|
||||
return ('500', 'text/plain', $filelist->{error}) if (defined $filelist->{error});
|
||||
$buf = '';
|
||||
return ('200', 'text/plain', "Done\n");
|
||||
}
|
||||
|
||||
sub __pdate {
|
||||
my @time = gmtime(time);
|
||||
my @DAYOFWEEK = qw(Sun Mon Tue Wed Thu Fri Sat);
|
||||
my @MONTH = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Nov Dec);
|
||||
return strftime "$DAYOFWEEK[$time[6]] $MONTH[$time[4] - 1] %e %T UTC %Y", @time;
|
||||
}
|
||||
|
||||
sub __trim ($) {
|
||||
my $str = shift;
|
||||
|
||||
while (substr ($str, 0, 1) =~ /^\s$/xms) {
|
||||
$str = substr ($str, 1);
|
||||
}
|
||||
|
||||
while (substr ($str, -1, 1) =~ /^\s$/xms) {
|
||||
chop ($str);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
sub __readfile ($) {
|
||||
my $file = shift;
|
||||
my $ret;
|
||||
|
||||
open (my $FILEHANDLE, '<', $file) or do {
|
||||
my $msg = "Unable to open file $file: $OS_ERROR";
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
};
|
||||
|
||||
binmode $FILEHANDLE;
|
||||
my $buf;
|
||||
my $len = (stat $file)[7];
|
||||
my $readlen = read ($FILEHANDLE, $buf, $len);
|
||||
close $FILEHANDLE; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||
|
||||
unless (defined $readlen) {
|
||||
my $msg = "Unable to read $file: $OS_ERROR";
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ($readlen != $len) {
|
||||
my $msg = "Unable to read $file: amount of read bytes does not match with file size";
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$ret->{data} = $buf;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub __writefile (@) {
|
||||
my $file = shift;
|
||||
my $dataref = shift;
|
||||
my $ret;
|
||||
|
||||
sysopen (my $FILEHANDLE, $file, O_WRONLY|O_TRUNC|O_CREAT) or do {
|
||||
my $msg = "Unable to open file $file: $OS_ERROR";
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
};
|
||||
|
||||
binmode $FILEHANDLE;
|
||||
|
||||
use bytes;
|
||||
my $len = length ${$dataref};
|
||||
no bytes;
|
||||
my $writelen = syswrite ($FILEHANDLE, ${$dataref}, $len);
|
||||
close $FILEHANDLE; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||
|
||||
unless (defined $writelen) {
|
||||
my $msg = "Unable to write $file: $OS_ERROR";
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ($writelen != $len) {
|
||||
my $msg = "Unable to write $file: amount of read bytes does not match with file size";
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$ret->{success} = 1;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub __dirlist ($) {
|
||||
my $dir = shift;
|
||||
my $res;
|
||||
my @files;
|
||||
|
||||
opendir (my $dirhandle, $dir) or do {
|
||||
my $msg = "Unable to open $dir: $OS_ERROR";
|
||||
carp "[FATA] $msg";
|
||||
$res->{error} = $msg;
|
||||
return $msg;
|
||||
};
|
||||
|
||||
while (readdir $dirhandle) {
|
||||
next unless (-f "$dir/$_");
|
||||
push @files, $_;
|
||||
}
|
||||
|
||||
closedir $dirhandle;
|
||||
@files = sort @files;
|
||||
$res->{dir} = \@files;
|
||||
return $res;
|
||||
}
|
||||
|
||||
sub __bzdata ($) {
|
||||
my $databufref = shift;
|
||||
my $ret;
|
||||
my $bzdata;
|
||||
my $bz = Compress::Raw::Bzip2->new (1, 9, 0);
|
||||
|
||||
unless (defined $bz) {
|
||||
my $msg = 'Unable to create bz object';
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ($bz->bzdeflate(${$databufref}, $bzdata) != BZ_RUN_OK) {
|
||||
my $msg = 'Unable to perofrm bzip2 compression';
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ($bz->bzflush($bzdata) != BZ_RUN_OK) {
|
||||
my $msg = 'Unable to flush bz buffer';
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ($bz->bzclose($bzdata) != BZ_STREAM_END) {
|
||||
my $msg = 'Unable to flush and close bz buffer';
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$ret->{data} = $bzdata;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub __gzdata ($) {
|
||||
my $databufref = shift;
|
||||
my $ret;
|
||||
my $gzdata;
|
||||
|
||||
my $gz = Compress::Raw::Zlib::Deflate->new (
|
||||
-Level => Z_BEST_COMPRESSION,
|
||||
-CRC32 => 1,
|
||||
-ADLER32=> 1,
|
||||
-WindowBits => WANT_GZIP
|
||||
);
|
||||
|
||||
unless (defined $gz) {
|
||||
my $msg = 'Unable to create gz object';
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ($gz->deflate(${$databufref}, $gzdata) != Z_OK) {
|
||||
my $msg = 'Unable to deflate';
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ($gz->flush($gzdata) != Z_OK) {
|
||||
my $msg = 'Unable to flush gz object';
|
||||
carp "[FATA] $msg";
|
||||
$ret->{error} = $msg;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
$ret->{data} = $gzdata;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set ft=perl noet ai ts=4 sw=4 sts=4 :
|
||||
99
Slackmetarep/Upload.pm
Normal file
99
Slackmetarep/Upload.pm
Normal file
@@ -0,0 +1,99 @@
|
||||
package Slackmetarep::Upload;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use vars qw/$VERSION/;
|
||||
use English qw( -no_match_vars );
|
||||
use Carp;
|
||||
|
||||
use Fcntl;
|
||||
use Slackmetarep::Conf qw(loadConf);
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT_OK = qw(upload);
|
||||
|
||||
$VERSION = '1.0';
|
||||
|
||||
my $c = loadConf ();
|
||||
|
||||
sub upload {
|
||||
my $input = shift; # file descriptor with data being uploaded
|
||||
my $len = shift; # expected data length (from client)
|
||||
my $name = shift; # upload "dir" and filename
|
||||
my ($status, $content, $msg) = ('400', 'text/plain', "Bad Request?\n");
|
||||
|
||||
return ($status, $content, "No Content-Length supplied.\n") unless (defined $len);
|
||||
return ($status, $content, "No name supplied.\n") unless (defined $name);
|
||||
|
||||
my $d;
|
||||
($d, $name) = split (/\//xms, $name, 2);
|
||||
|
||||
return ($status, $content, "Name does not match pattern.\n") unless ($name =~ /^[[:alnum:]_\-\+\.]+$/xmsg);
|
||||
|
||||
my $match;
|
||||
|
||||
foreach my $uploaddir (keys(%{$c->{upload}->{dir}})) {
|
||||
if ($d eq $uploaddir) {
|
||||
$match = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
return ($status, $content, "Incorrect destination dir.\n") unless $match; # incorrect destination in url
|
||||
|
||||
$name = sprintf('%s/%s', $c->{upload}->{dir}->{$d}, $name);
|
||||
|
||||
if ($len > 0) {
|
||||
if (sysopen (my $FH, $name, O_CREAT|O_TRUNC|O_WRONLY)) {
|
||||
my $buf;
|
||||
my $readlen = 0;
|
||||
my $totalread = 0;
|
||||
my $buflen = 524288; # 512 kbytes, looks sane enough
|
||||
|
||||
if ($len < $buflen) {
|
||||
$buflen = $len;
|
||||
}
|
||||
|
||||
do {
|
||||
$readlen = $input->read($buf, $buflen);
|
||||
|
||||
my $written = syswrite $FH, $buf, $readlen;
|
||||
|
||||
unless (defined($written)) { # out of space?
|
||||
close $FH; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||
unlink $name;
|
||||
carp "[FATA] Unable to write to $name: $OS_ERROR";
|
||||
return ('500', $content, "An error has occured during upload: $OS_ERROR\n");
|
||||
}
|
||||
|
||||
if ($readlen != $written) {
|
||||
close $FH; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||
unlink $name;
|
||||
carp "[FATA] Must write $readlen bytes, but actualy wrote $written bytes to $name";
|
||||
return ('500', $content, "An error has occured during upload: $OS_ERROR\n");
|
||||
}
|
||||
|
||||
$totalread += $readlen;
|
||||
} while ($readlen == $buflen);
|
||||
|
||||
close $FH; ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||
|
||||
if ($totalread != $len) {
|
||||
($content, $msg) = ($content, "Content-Length does not match amount of recieved bytes.\n");
|
||||
} else {
|
||||
($status, $content, $msg) = ('201', $content, "Uploaded.\n");
|
||||
}
|
||||
} else {
|
||||
carp "[FATA] Unable to open file $name: $OS_ERROR";
|
||||
($status, $content, $msg) = ('500', $content, "Unable to write: $OS_ERROR\n");
|
||||
}
|
||||
} else {
|
||||
$msg = "Incorrect Content-Length\n";
|
||||
}
|
||||
|
||||
return ($status, $content, $msg);
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
# vim: set ft=perl noet ai ts=4 sw=4 sts=4 :
|
||||
5
bootstrap.sh
Normal file
5
bootstrap.sh
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
cpanm -l vendor_perl --self-contained --force --update --installdeps .
|
||||
|
||||
# vim: set ft=sh noet ai ts=4 sw=4 sts=4:
|
||||
20
confcheck.pl
Executable file
20
confcheck.pl
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use 5.018;
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
use open qw(:std :utf8);
|
||||
use English qw( -no_match_vars );
|
||||
use JSON::XS;
|
||||
use lib qw(./vendor_perl ./vendor_perl/lib/perl5);
|
||||
|
||||
use Slackmetarep::Conf;
|
||||
|
||||
use version; our $VERSION = qv(1.0);
|
||||
|
||||
my $CONF = loadConf();
|
||||
my $j = JSON::XS->new->pretty->canonical->indent(1);
|
||||
say $j->encode ($CONF); ## no critic (InputOutput::RequireCheckedSyscalls)
|
||||
|
||||
# vim: set ft=perl noet ai ts=4 sw=4 sts=4:
|
||||
8
cpanfile
Normal file
8
cpanfile
Normal file
@@ -0,0 +1,8 @@
|
||||
requires 'Compress::Raw::Bzip2';
|
||||
requires 'Compress::Raw::Zlib';
|
||||
requires 'Exporter';
|
||||
requires 'Fcntl';
|
||||
requires 'JSON::XS';
|
||||
requires 'POSIX';
|
||||
requires 'Plack::Util';
|
||||
requires 'local::lib';
|
||||
25
data/sample_config.json
Normal file
25
data/sample_config.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"api" : {
|
||||
"prefix" : "/api"
|
||||
},
|
||||
"upload" : {
|
||||
"dir" : {
|
||||
"thrirdparty": "/var/www/REPO/slackware/thrird-party/14.2/x86_64",
|
||||
"thrird-party": "/var/www/REPO/slackware/thrird-party/14.2/x86_64",
|
||||
"slackbuild-thrird-party": "/var/www/REPO/slackware/thrird-party/14.2/x86_64",
|
||||
"slackbuild-thrirdparty": "/var/www/REPO/slackware/thrird-party/14.2/x86_64"
|
||||
},
|
||||
"auth": "welcometothejungle"
|
||||
},
|
||||
"metagen" : {
|
||||
"thrirdparty" : "/var/www/REPO/slackware/thrird-party/14.2/x86_64",
|
||||
"thrird-party" : "/var/www/REPO/slackware/thrird-party/14.2/x86_64",
|
||||
"slackbuild-thrird-party" : "/var/www/REPO/slackware/thrird-party/14.2/x86_64",
|
||||
"slackbuild-thrirdparty" : "/var/www/REPO/slackware/thrird-party/14.2/x86_64"
|
||||
},
|
||||
"buildinfo" : {
|
||||
"thrirdparty" : "/var/www/config-slackbuild-thrird-party.json",
|
||||
"slackbuild-thrirdparty" : "/var/www/config-slackbuild-thrird-party.json",
|
||||
"slackbuild-thrird-party" : "/var/www/config-slackbuild-thrird-party.json"
|
||||
}
|
||||
}
|
||||
303
docs/metadata_en.md
Normal file
303
docs/metadata_en.md
Normal file
@@ -0,0 +1,303 @@
|
||||
# Metadata of slackware packages repository
|
||||
|
||||
To install packages from repository, repository package list is required. Also description is desired. All this infrmation called metadata.
|
||||
|
||||
## Standard metadata format
|
||||
|
||||
Metadata from DVD and in official repo in internet both identical. Format od data by itself allows some variations.
|
||||
|
||||
Metadata is split across some files for ease of it creation and parsing.
|
||||
|
||||
### list of metadata files in main repo
|
||||
|
||||
**CHECKSUMS.md5, CHECKSUMS.md5.asc, ChangeLog.txt, FILELIST.TXT, GPG-KEY, PACKAGES.TXT**
|
||||
|
||||
### List of metadata files in sub-repos
|
||||
|
||||
There are sub-repositories in main repository pool, it just sub-dirs here with its own pack of metadata files. It is: patches, pasture, extra.
|
||||
|
||||
**Patches** - updates.
|
||||
|
||||
**Pasture** - obsoleted packages that have compatibility issues, not supported by authors or for other reasons are not included in main packages list.
|
||||
|
||||
**Extra** - new or alternative packages that for some reasons not in main package list.
|
||||
|
||||
Sub-repository **patches** exist only in release version of distro. There is no patches in -current.
|
||||
|
||||
There is different metadata files in sub-repo:
|
||||
**CHECKSUMS.md5, CHECKSUMS.md5.asc, FILE_LIST, MANIFEST.bz2, PACKAGES.TXT.**
|
||||
|
||||
### Metadata description
|
||||
|
||||
#### CHECKSUMS.md5
|
||||
|
||||
This is md5-checksim for each file in repository available at the moment of CHECKSUM.m5 creation. Header of this file contains instruction how check yoour copy intergity:
|
||||
|
||||
```text
|
||||
These are the MD5 message digests for the files in this directory.
|
||||
If you want to test your files, use 'md5sum' and compare the values to
|
||||
the ones listed here.
|
||||
|
||||
To test all these files, use this command:
|
||||
|
||||
tail +13 CHECKSUMS.md5 | md5sum -c --quiet - | less
|
||||
|
||||
'md5sum' can be found in the GNU coreutils package on ftp.gnu.org in
|
||||
/pub/gnu, or at any GNU mirror site.
|
||||
|
||||
MD5 message digest Filename
|
||||
```
|
||||
|
||||
There is 1 extra new line between header and actual data. There is no enpty lines in the body of this file.
|
||||
|
||||
```text
|
||||
2c4180b57c277ad3cd38865a466a4c15 ./ANNOUNCE.14_2
|
||||
85891676a985eb6c87170083e1df75de ./CHANGES_AND_HINTS.TXT
|
||||
```
|
||||
|
||||
and so on for all other files. Important checksums here is only for packages itselves, accompanying .txt and respective asc files. MD5 for other files can be ommited.
|
||||
|
||||
***Notes to format of this file:***
|
||||
|
||||
* first, no empty lined allowed in data body
|
||||
* second, there must be exactly one newline after last record in file
|
||||
* thrird, file name always begins with "./" (no quotes).
|
||||
|
||||
#### CHECKSUMS.md5.asc
|
||||
|
||||
This file sries gpg signature for CHECKSUMS.md5.
|
||||
|
||||
GPG signature is highly desired but not required. It ensures that packages with matching md5 is authored and placed to repository by owner of closed part of gpg key. In other word it ensures that package is genuine.
|
||||
|
||||
#### ChangeLog.txt
|
||||
|
||||
All package changes are stored in this file. This file exist in main repo and contains also changes that made to sub-repostory.
|
||||
|
||||
Changes are recorded here in "batches":
|
||||
|
||||
```text
|
||||
Sat Nov 2 18:52:12 UTC 2019
|
||||
a/aaa_terminfo-6.1_20191026-x86_64-1.txz: Upgraded.
|
||||
a/cryptsetup-2.2.2-x86_64-1.txz: Upgraded.
|
||||
a/lvm2-2.03.06-x86_64-1.txz: Upgraded.
|
||||
d/Cython-0.29.14-x86_64-1.txz: Upgraded.
|
||||
l/ncurses-6.1_20191026-x86_64-1.txz: Upgraded.
|
||||
Restore the --without-normal option to skip static libraries as used in 14.2.
|
||||
Thanks to Richard Narron.
|
||||
x/xterm-349-x86_64-2.txz: Rebuilt.
|
||||
In /etc/app-defaults/XTerm, use terminus-medium instead of terminus-bold.
|
||||
Thanks to igadoter.
|
||||
+--------------------------+
|
||||
```
|
||||
|
||||
Note the delimeter at the bottom of the batch.
|
||||
This file is optional and can be found not only in official repo but for example in AlienBob's. By the way in AlienBob's reop this file also *begins* with delimeter and contains extra newline between batches.
|
||||
|
||||
#### FILELIST.TXT
|
||||
|
||||
List of all files in repository. Means all related files for endusers, but as a rule it contains all files in repository.
|
||||
|
||||
Thist file contains header:
|
||||
|
||||
```text
|
||||
Sat Nov 2 19:03:12 UTC 2019
|
||||
|
||||
Here is the file list for this directory. If you are using a
|
||||
mirror site and find missing or extra files in the disk
|
||||
subdirectories, please have the archive administrator refresh
|
||||
the mirror.
|
||||
|
||||
```
|
||||
|
||||
Note the date of file generation and one extra new line after header.
|
||||
|
||||
File body looks like that:
|
||||
|
||||
```text
|
||||
drwxr-xr-x 12 root root 4096 2019-11-02 18:52 .
|
||||
-rw-r--r-- 1 root root 10064 2016-06-30 18:39 ./ANNOUNCE.14_2
|
||||
-rw-r--r-- 1 root root 14642 2019-10-18 21:18 ./CHANGES_AND_HINTS.TXT
|
||||
```
|
||||
|
||||
Similar listing you can get by invoking next command:
|
||||
|
||||
```bash
|
||||
ls -lAn --time-style=long-iso "$dir"
|
||||
```
|
||||
|
||||
but please note that in ls output there is no "." directory and file path will not begin with "./" which is required.
|
||||
|
||||
File must end with newline symbol.
|
||||
|
||||
#### GPG-KEY
|
||||
|
||||
This is public part of GPG-key you can check integrity of files that is signed with apropiate closed key (files with satelite files with **.asc** extension).
|
||||
|
||||
How to use it:
|
||||
|
||||
Check the key for correctness:
|
||||
|
||||
```bash
|
||||
gpg --keyid-format long --show-key GPG-KEY
|
||||
```
|
||||
|
||||
Import it to our keyring:
|
||||
|
||||
```bash
|
||||
gpg --import GPG-KEY
|
||||
```
|
||||
|
||||
Then check:
|
||||
|
||||
```bash
|
||||
gpg --verify CHECKSUMS.md5.asc CHECKSUMS.md5
|
||||
```
|
||||
|
||||
#### PACKAGES.TXT
|
||||
|
||||
Repository packages list (kind of). Classic header looks like this:
|
||||
|
||||
```text
|
||||
|
||||
PACKAGES.TXT; Sat Nov 2 19:01:20 UTC 2019
|
||||
|
||||
This file provides details on the Slackware packages found
|
||||
in the ./slackware64/ directory.
|
||||
|
||||
Total size of all packages (compressed): 2612 MB
|
||||
Total size of all packages (uncompressed): 11323 MB
|
||||
|
||||
|
||||
```
|
||||
|
||||
Header begins with newline and ends with 2 newlines.
|
||||
|
||||
Technically whole header can be "compressed" to this form withoun any loss:
|
||||
|
||||
```text
|
||||
PACKAGES.TXT; Sun Nov 3 12:47:53 UTC 2019
|
||||
|
||||
```
|
||||
|
||||
In this particular case file does not begin with newline and contains only one newline in the end of header. AlienBob do it like this.
|
||||
|
||||
Body itself consists of batches of strings related to each package. Batch separator is extra newline. Example of package record from official repository:
|
||||
|
||||
```text
|
||||
PACKAGE NAME: ConsoleKit2-1.0.0-x86_64-4.txz
|
||||
PACKAGE LOCATION: ./slackware64/l
|
||||
PACKAGE SIZE (compressed): 148 K
|
||||
PACKAGE SIZE (uncompressed): 780 K
|
||||
PACKAGE DESCRIPTION:
|
||||
ConsoleKit2: ConsoleKit2 (user, login, and seat tracking framework)
|
||||
ConsoleKit2:
|
||||
ConsoleKit2: ConsoleKit2 is a framework for defining and tracking users, login
|
||||
ConsoleKit2: sessions, and seats.
|
||||
ConsoleKit2:
|
||||
ConsoleKit2: Homepage: https://github.com/ConsoleKit2/ConsoleKit2
|
||||
ConsoleKit2:
|
||||
```
|
||||
|
||||
Example from thrird-party repo:
|
||||
|
||||
```text
|
||||
PACKAGE NAME: SDL2-2.0.10-x86_64-1.txz
|
||||
PACKAGE LOCATION: .
|
||||
PACKAGE SIZE (compressed): 609 K
|
||||
PACKAGE SIZE (uncompressed): 3260 K
|
||||
PACKAGE REQUIRED:
|
||||
PACKAGE CONFLICTS:
|
||||
PACKAGE SUGGESTS:
|
||||
PACKAGE DESCRIPTION:
|
||||
SDL2:
|
||||
SDL2: Simple DirectMedia Layer is a cross-platform development library
|
||||
SDL2: designed to provide low-level access to audio, keyboard, mouse,
|
||||
SDL2: joystick, and graphics hardware ia via OpenGL. It is used by
|
||||
SDL2: video playback software, emulators, and games.
|
||||
SDL2:
|
||||
SDL2: Homepage: http://www.libsdl.org
|
||||
SDL2:
|
||||
SDL2:
|
||||
SDL2:
|
||||
```
|
||||
|
||||
As you can see everythin that goes after "PACKAGE DESCRIPTION:" is contents of apropriate slack-desc from package.
|
||||
|
||||
Also thrird party repository contains extended metainformation - dependencies, conflicts and recommended packages.
|
||||
|
||||
In official repository this file ends with 2 newlines, AlienBob makes only one and it works fine.
|
||||
|
||||
#### MANIFEST.bz2
|
||||
|
||||
In official repository it is placed only in sub-repositries, for thrird-parties it placed in main repository.
|
||||
|
||||
It doesen't contain any header. All records are separated by extra 2 newlines. File ends with 2 extra newlines.
|
||||
|
||||
Example of one record:
|
||||
|
||||
```text
|
||||
++========================================
|
||||
||
|
||||
|| Package: ./aspell-word-lists/aspell-am-0.03_1-x86_64-5.txz
|
||||
||
|
||||
++========================================
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 ./
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 install/
|
||||
-rw-r--r-- root/root 190 2016-06-06 15:13 install/slack-desc
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 usr/
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 usr/lib64/
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 usr/lib64/aspell/
|
||||
-rw-r--r-- root/root 101 2016-06-06 15:13 usr/lib64/aspell/am.dat
|
||||
-rw-r--r-- root/root 282544 2016-06-06 15:13 usr/lib64/aspell/am.rws
|
||||
-rw-r--r-- root/root 426 2016-06-06 15:13 usr/lib64/aspell/am_affix.dat
|
||||
-rw-r--r-- root/root 1871 2016-06-06 15:13 usr/lib64/aspell/am_phonet.dat
|
||||
-rw-r--r-- root/root 72 2016-06-06 15:13 usr/lib64/aspell/amharic.alias
|
||||
-rw-r--r-- root/root 25615 2016-06-06 15:13 usr/lib64/aspell/s-ethi.cmap
|
||||
-rw-r--r-- root/root 70 2016-06-06 15:13 usr/lib64/aspell/am.multi
|
||||
-rw-r--r-- root/root 13356 2016-06-06 15:13 usr/lib64/aspell/s-ethi.cset
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 usr/doc/
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 usr/doc/aspell-am-0.03_1/
|
||||
-rw-r--r-- root/root 394 2004-12-22 20:27 usr/doc/aspell-am-0.03_1/Copyright
|
||||
-rw-r--r-- root/root 2434 2004-12-28 08:15 usr/doc/aspell-am-0.03_1/README
|
||||
```
|
||||
|
||||
## Metadata format extensions
|
||||
|
||||
As extension to official repo it may note existance of gzipped files: CHECKSUMS.md5.gz ChangeLog.txt.gz PACKAGES.TXT.gz. In case of gpg signature of uncompressed files exist, it also must me generated for compressed files too.
|
||||
|
||||
There is additional fields in PACKAGES.TXT:
|
||||
|
||||
```text
|
||||
PACKAGE REQUIRED:
|
||||
PACKAGE CONFLICTS:
|
||||
PACKAGE SUGGESTS:
|
||||
```
|
||||
|
||||
Their purpos is obviously more flexible package management.
|
||||
|
||||
## Methods of repo metsdata creation
|
||||
|
||||
There is to approaches to metadata generation:
|
||||
|
||||
* lazy - made with pre-generated additional information chunks (or database) that are gathered durin package build process.
|
||||
* full - extract all metadata directly from packages.
|
||||
|
||||
### Lazy method
|
||||
|
||||
It been used by AlienBob in his repo. Some additional files being generated during package build process and being uploaded to repository. When repository metadata generator run, it parses these additional files and makes metadata for repo.
|
||||
|
||||
It is also possible to store additional metainformation abaout packages in some sort of database for same puposes.
|
||||
|
||||
There is some benefits in this approach. It is faster to parse pre-generated metadata than extract it from package. it is especially notable on large repositories.
|
||||
|
||||
As a side effect there are some extra files in repository. But you can mitigate it by using database, but it adds some complexity to solution of repo metadata problem.
|
||||
|
||||
### Full data methos
|
||||
|
||||
I do not know application area of this method. But official repositories does not contain any extra files.
|
||||
|
||||
This method suits for small repositories.
|
||||
|
||||
Tradeoffs of this method is cpu and disk intensive process of metadata generation because of package unpacking and inspection occurs during metadata generation.
|
||||
|
||||
Benefits is obvious. You need no extra files in repo, just packages itselves.
|
||||
298
docs/metadata_ru.md
Normal file
298
docs/metadata_ru.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# Метаданные репозитория
|
||||
|
||||
Чтобы установить пакеты из репозитория, необходимо знать список пакетов, которые там есть, кроме того желательно иметь описание для каждого пакета и некоторую техническую информацию.
|
||||
|
||||
## Стандартный формат метаданных
|
||||
|
||||
Метаданные на DVD ROM и в официальном репозитории в интернете по своему формату одинаковые. Сам по себе формат допускает некоторые небольшие вольности, подозреваю, что это связано с тем, что разбор этих данных происходит стандартными утилитами командной строки, которые позволяют в некоторых местах использовать относительно "свободный" формат.
|
||||
|
||||
Метаданные размещены в нескольких текстовых файлах, для простоты их генерации и разбора.
|
||||
|
||||
### Список файлов метаданных основного репозитория
|
||||
|
||||
**CHECKSUMS.md5, CHECKSUMS.md5.asc, ChangeLog.txt, FILELIST.TXT, GPG-KEY, PACKAGES.TXT**
|
||||
|
||||
### Список файлов метаданных суб-репозиториев
|
||||
|
||||
Суб-репозитории - это подкаталоги с тематической подборкой пакетов. Их бывает 3: patches, pasture, extra.
|
||||
|
||||
**Patches** - это обновления.
|
||||
|
||||
**Pasture** - это пакеты, которые были в прошлых выпусках дистрибутива, но не вошли в текущий по тем или иным причинам.
|
||||
|
||||
**Extra** - это новые пакеты, которые были предложены к использованию в текущем выпуске, но по тем или иным причинам не были включены в основной список пакетов.
|
||||
|
||||
Суб-репозиторий **patches** присутствует только в репозитории с релизным вариантом дистрибутива, то есть его нет, например, в репозитории -current.
|
||||
|
||||
Метаданные субрепозиториев немного отличаются.
|
||||
**CHECKSUMS.md5, CHECKSUMS.md5.asc, FILE_LIST, MANIFEST.bz2, PACKAGES.TXT.**
|
||||
|
||||
### Описание метаданных
|
||||
|
||||
#### CHECKSUMS.md5
|
||||
|
||||
Это файл с checksum-ами в формате md5, в заголовке файла есть описание, как его сгенерировать:
|
||||
|
||||
```text
|
||||
These are the MD5 message digests for the files in this directory.
|
||||
If you want to test your files, use 'md5sum' and compare the values to
|
||||
the ones listed here.
|
||||
|
||||
To test all these files, use this command:
|
||||
|
||||
tail +13 CHECKSUMS.md5 | md5sum -c --quiet - | less
|
||||
|
||||
'md5sum' can be found in the GNU coreutils package on ftp.gnu.org in
|
||||
/pub/gnu, or at any GNU mirror site.
|
||||
|
||||
MD5 message digest Filename
|
||||
```
|
||||
|
||||
После заголовка идёт 1 перенос строки, то есть между последней строкой заголовка и первой строкой тела этого файла пустых строк нет.
|
||||
|
||||
Само тело это действительно вывод указанной команды:
|
||||
|
||||
```text
|
||||
2c4180b57c277ad3cd38865a466a4c15 ./ANNOUNCE.14_2
|
||||
85891676a985eb6c87170083e1df75de ./CHANGES_AND_HINTS.TXT
|
||||
```
|
||||
|
||||
и так далее для всех файлов в репозитории. Значимыми здесь являются файлы пакетов и сопровождающие их asc и txt файлы. Остальные - за компанию, для них вычислять md5 необязательно.
|
||||
|
||||
***Замечания к формату тела файла:***
|
||||
|
||||
* во-первых, не должно быть пустых строк
|
||||
* во вторых, файл чётко должен заканчиваться на один снос строки, после последней записи
|
||||
* в третьих, имя файла относительно и всегда начинается на "./" (без кавычек).
|
||||
|
||||
#### CHECKSUMS.md5.asc
|
||||
|
||||
В этом файле хранится gpg-подпись для CHECKSUMS.md5.
|
||||
|
||||
GPG-подпись желательна, но не обязательна. Она удостоверяет, что пакет был положен в репозиторий владельцем закрытого gpg-ключа, соответственно, он подлинный.
|
||||
|
||||
#### ChangeLog.txt
|
||||
|
||||
Здесь записываются все изменения. Этот файл встречается в основном репозитории и в него входят изменения, в том числе внесённые в суб-репозитории.
|
||||
|
||||
Изменения записываются "пачками":
|
||||
|
||||
```text
|
||||
Sat Nov 2 18:52:12 UTC 2019
|
||||
a/aaa_terminfo-6.1_20191026-x86_64-1.txz: Upgraded.
|
||||
a/cryptsetup-2.2.2-x86_64-1.txz: Upgraded.
|
||||
a/lvm2-2.03.06-x86_64-1.txz: Upgraded.
|
||||
d/Cython-0.29.14-x86_64-1.txz: Upgraded.
|
||||
l/ncurses-6.1_20191026-x86_64-1.txz: Upgraded.
|
||||
Restore the --without-normal option to skip static libraries as used in 14.2.
|
||||
Thanks to Richard Narron.
|
||||
x/xterm-349-x86_64-2.txz: Rebuilt.
|
||||
In /etc/app-defaults/XTerm, use terminus-medium instead of terminus-bold.
|
||||
Thanks to igadoter.
|
||||
+--------------------------+
|
||||
```
|
||||
|
||||
Файл опционален, он входит в состав не только официальных репозиториев, но и встречается, например, у AlienBob-а. Кстати, у последнего этот файл начинается с разделителя и после каждой "пачки" вставляется дополнительная пустая строка.
|
||||
|
||||
#### FILELIST.TXT
|
||||
|
||||
Список всех файлов в репозитории. Имеются в виду, конечно, значимые файлы, но, как правило, генерят просто список всех файлов, начиная с корня репозитория.
|
||||
|
||||
Файл содержит следующий заголовок:
|
||||
|
||||
```text
|
||||
Sat Nov 2 19:03:12 UTC 2019
|
||||
|
||||
Here is the file list for this directory. If you are using a
|
||||
mirror site and find missing or extra files in the disk
|
||||
subdirectories, please have the archive administrator refresh
|
||||
the mirror.
|
||||
|
||||
```
|
||||
|
||||
После заголовка и перед телом файла присутствует пустая строка.
|
||||
|
||||
Тело файла выглядит примерно так:
|
||||
|
||||
```text
|
||||
drwxr-xr-x 12 root root 4096 2019-11-02 18:52 .
|
||||
-rw-r--r-- 1 root root 10064 2016-06-30 18:39 ./ANNOUNCE.14_2
|
||||
-rw-r--r-- 1 root root 14642 2019-10-18 21:18 ./CHANGES_AND_HINTS.TXT
|
||||
```
|
||||
|
||||
похожий список можно получить в выводе команды:
|
||||
|
||||
```bash
|
||||
ls -lAn --time-style=long-iso "$dir"
|
||||
```
|
||||
|
||||
однако в выводе не будет каталога "." и все файлы не будут начинаться "./".
|
||||
|
||||
Файл заканчивается на снос строки.
|
||||
|
||||
#### GPG-KEY
|
||||
|
||||
Это публичная часть ключа, с помощью которой можно проверять целостность файлов, подписанных gpg (при которых присутствует файл-сателлит с расширением **.asc**).
|
||||
|
||||
А воспользоваться этим инструментом можно примерно так:
|
||||
|
||||
Проверяем, что ключ правильный:
|
||||
|
||||
```text
|
||||
gpg --keyid-format long --show-key GPG-KEY
|
||||
```
|
||||
|
||||
Импортируем его к себе в keyring:
|
||||
|
||||
```text
|
||||
gpg --import GPG-KEY
|
||||
```
|
||||
|
||||
Собственно, проверяем:
|
||||
|
||||
```text
|
||||
gpg --verify CHECKSUMS.md5.asc CHECKSUMS.md5
|
||||
```
|
||||
|
||||
#### PACKAGES.TXT
|
||||
|
||||
Список пакетов в репозитории. Классический заголовок файла выглядит так:
|
||||
|
||||
```text
|
||||
|
||||
PACKAGES.TXT; Sat Nov 2 19:01:20 UTC 2019
|
||||
|
||||
This file provides details on the Slackware packages found
|
||||
in the ./slackware64/ directory.
|
||||
|
||||
Total size of all packages (compressed): 2612 MB
|
||||
Total size of all packages (uncompressed): 11323 MB
|
||||
|
||||
|
||||
```
|
||||
|
||||
Заголовок файла начинается с пустой строки, а заканчивается 2 (*двумя!*) пустыми строками.
|
||||
|
||||
Технически это всё свободно (без потери работоспособности) может ужиматься до такой записи:
|
||||
|
||||
```text
|
||||
PACKAGES.TXT; Sun Nov 3 12:47:53 UTC 2019
|
||||
|
||||
```
|
||||
|
||||
В этом случае заголовок не начинается с пустой строки и заканчивается на одну пустую строку. Так делает AlienBob.
|
||||
|
||||
Само тело состоит из записей (набор строк), разделённых пустой строкой. Пример записи из основного репозитория:
|
||||
|
||||
```text
|
||||
PACKAGE NAME: ConsoleKit2-1.0.0-x86_64-4.txz
|
||||
PACKAGE LOCATION: ./slackware64/l
|
||||
PACKAGE SIZE (compressed): 148 K
|
||||
PACKAGE SIZE (uncompressed): 780 K
|
||||
PACKAGE DESCRIPTION:
|
||||
ConsoleKit2: ConsoleKit2 (user, login, and seat tracking framework)
|
||||
ConsoleKit2:
|
||||
ConsoleKit2: ConsoleKit2 is a framework for defining and tracking users, login
|
||||
ConsoleKit2: sessions, and seats.
|
||||
ConsoleKit2:
|
||||
ConsoleKit2: Homepage: https://github.com/ConsoleKit2/ConsoleKit2
|
||||
ConsoleKit2:
|
||||
```
|
||||
|
||||
Пример записи из стороннего репозитория:
|
||||
|
||||
```text
|
||||
PACKAGE NAME: SDL2-2.0.10-x86_64-1.txz
|
||||
PACKAGE LOCATION: .
|
||||
PACKAGE SIZE (compressed): 609 K
|
||||
PACKAGE SIZE (uncompressed): 3260 K
|
||||
PACKAGE REQUIRED:
|
||||
PACKAGE CONFLICTS:
|
||||
PACKAGE SUGGESTS:
|
||||
PACKAGE DESCRIPTION:
|
||||
SDL2:
|
||||
SDL2: Simple DirectMedia Layer is a cross-platform development library
|
||||
SDL2: designed to provide low-level access to audio, keyboard, mouse,
|
||||
SDL2: joystick, and graphics hardware ia via OpenGL. It is used by
|
||||
SDL2: video playback software, emulators, and games.
|
||||
SDL2:
|
||||
SDL2: Homepage: http://www.libsdl.org
|
||||
SDL2:
|
||||
SDL2:
|
||||
SDL2:
|
||||
```
|
||||
|
||||
как видим, всё, что идёт после "PACKAGE DESCRIPTION:" - это фрагмент файла slack-desc с описанием пакета.
|
||||
|
||||
Соответственно, сторонний репозиторий содержит расширенную информацию: зависимости, конфликты, рекомендованные пакеты
|
||||
|
||||
В случае официального репозитория, файл заканчивается на 2 пустые строки. AlienBob в своём стороннем репозитории довольствуется одной пустой строкой и это работает.
|
||||
|
||||
#### MANIFEST.bz2
|
||||
|
||||
Для официального репозитория он лежит только в суб-репозиториях, для сторонних репозиториев его кладут в основной репозиторий. Содержит список файлов в пакете.
|
||||
|
||||
Не содержит заголовка. Записи разделяются двумя пустыми строками.
|
||||
|
||||
```text
|
||||
++========================================
|
||||
||
|
||||
|| Package: ./aspell-word-lists/aspell-am-0.03_1-x86_64-5.txz
|
||||
||
|
||||
++========================================
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 ./
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 install/
|
||||
-rw-r--r-- root/root 190 2016-06-06 15:13 install/slack-desc
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 usr/
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 usr/lib64/
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 usr/lib64/aspell/
|
||||
-rw-r--r-- root/root 101 2016-06-06 15:13 usr/lib64/aspell/am.dat
|
||||
-rw-r--r-- root/root 282544 2016-06-06 15:13 usr/lib64/aspell/am.rws
|
||||
-rw-r--r-- root/root 426 2016-06-06 15:13 usr/lib64/aspell/am_affix.dat
|
||||
-rw-r--r-- root/root 1871 2016-06-06 15:13 usr/lib64/aspell/am_phonet.dat
|
||||
-rw-r--r-- root/root 72 2016-06-06 15:13 usr/lib64/aspell/amharic.alias
|
||||
-rw-r--r-- root/root 25615 2016-06-06 15:13 usr/lib64/aspell/s-ethi.cmap
|
||||
-rw-r--r-- root/root 70 2016-06-06 15:13 usr/lib64/aspell/am.multi
|
||||
-rw-r--r-- root/root 13356 2016-06-06 15:13 usr/lib64/aspell/s-ethi.cset
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 usr/doc/
|
||||
drwxr-xr-x root/root 0 2016-06-06 15:13 usr/doc/aspell-am-0.03_1/
|
||||
-rw-r--r-- root/root 394 2004-12-22 20:27 usr/doc/aspell-am-0.03_1/Copyright
|
||||
-rw-r--r-- root/root 2434 2004-12-28 08:15 usr/doc/aspell-am-0.03_1/README
|
||||
```
|
||||
|
||||
## Расширения стандартного формата метаданных
|
||||
|
||||
В качестве расширения к официальному формату можно указать наличие сжатых версий файлов CHECKSUMS.md5.gz ChangeLog.txt.gz PACKAGES.TXT.gz. В данном случае если у несжатой версии есть подпись в asc-файле, то подписывать надо и сжатый файл тоже.
|
||||
|
||||
Кроме дополнительных сжатых файлов появились новые поля в PACKAGES.TXT:
|
||||
|
||||
```text
|
||||
PACKAGE REQUIRED:
|
||||
PACKAGE CONFLICTS:
|
||||
PACKAGE SUGGESTS:
|
||||
```
|
||||
|
||||
Их назначение вполне очевидно - более гибкое и более "умное" управление процессом установки пакетов.
|
||||
|
||||
## Подходы к генерации метаданных
|
||||
|
||||
Технически есть 2 метода генерации метаданных:
|
||||
|
||||
* Ленивый - с помощью подготовленных файликов, содержащих максимум метаинформации (либо с помощью БД) эта информация собирается в процессе подготовки пакета
|
||||
* Полный - извлечение метаинформации непосредственно из готовых пакетов.
|
||||
|
||||
### Ленивый подход
|
||||
|
||||
Его применяет AlienBob в своём репозитории. В процессе сборки пакета генерируется несколько дополнительных файликов, из которых в последствии извлекается информация для создания метаданных репозитория. Возможен другой вариант - складывать метаданные о пакете в БД и в процессе генерации метаданных о репозитории извлекать информацию о каждом пакете уже из неё.
|
||||
|
||||
К плюсам этого подхода можно отнести прежде всего дешевизну его использования, так как по файликам с подготовленными данными пробегаться значительно проще и быстрее, чем распаковывать каждый пакет и из полученных данных строит метаданные для репозитория, это особенно заметно на больших пакетах.
|
||||
|
||||
К минусам этого подхода можно отнести его неуниверсальность и наличие в репозитории дополнительных артефактов, впрочем, последнее можно нивелировать, задействовав БД как хранилище промежуточной метаинформации.
|
||||
|
||||
### Полный подход
|
||||
|
||||
Область применения - затрудняюсь сказать. Однако официальные репозитории не содержат дополнительных артефактов.
|
||||
|
||||
Этот подход вполне подходит для небольших репозиториев, так как позволяет генерировать метаданные из любой кучки пакетов.
|
||||
|
||||
К минусам этого подхода очевидно имеет смысл приписать его дороговизну как по iops-ам, так и по процессору: на каждую перегенерацию метаданных придётся распаковывать весь набор пакетов в репозитории.
|
||||
61
slackmetarep.psgi
Normal file
61
slackmetarep.psgi
Normal file
@@ -0,0 +1,61 @@
|
||||
## no critic (Modules::RequireExplicitPackage)
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# my plugins
|
||||
use lib qw(. ./vendor_perl ./vendor_perl/lib/perl5);
|
||||
use Slackmetarep::Conf qw(loadConf);
|
||||
use Slackmetarep::Upload qw(upload);
|
||||
use Slackmetarep::Metagen qw(metagen);
|
||||
use Slackmetarep::Buildinfo qw(buildinfo);
|
||||
|
||||
use version; our $VERSION = qv(1.0);
|
||||
|
||||
my $CONF = loadConf ();
|
||||
|
||||
if ($CONF->{api}->{prefix} eq '/') { $CONF->{api}->{prefix} = ''; }
|
||||
my $prefix = $CONF->{api}->{prefix};
|
||||
|
||||
# that is not module.
|
||||
my $app = sub { ## no critic (Modules::RequireEndWithOne)
|
||||
my $env = shift;
|
||||
|
||||
my $msg = "Your Opinion is very important for us, please stand by.\n";
|
||||
my $status = '404';
|
||||
my $content = 'text/plain';
|
||||
|
||||
if ($env->{PATH_INFO} =~ /$prefix\/upload\/(.+)/xmsg) {
|
||||
my $upload = $1;
|
||||
($status, $content, $msg) = ('400', $content, "Bad Request?\n");
|
||||
|
||||
if (defined($env->{HTTP_AUTH}) && ($env->{HTTP_AUTH} eq $CONF->{upload}->{auth})) {
|
||||
if (($upload !~ /\.\./xmsg) && ($upload =~ /^[_\-\+\/\.[:alnum:]]+$/xmsg)) {
|
||||
if (defined($env->{CONTENT_LENGTH}) && ($env->{CONTENT_LENGTH} > 0)) {
|
||||
($status, $content, $msg) = upload ($env->{'psgi.input'}, $env->{CONTENT_LENGTH}, $upload);
|
||||
}
|
||||
} else {
|
||||
$msg = "Something wrong with upload path.\n";
|
||||
}
|
||||
} else {
|
||||
($status, $content, $msg) = ('403', $content, "You're not allowed here. Fuck off.\n");
|
||||
}
|
||||
} elsif ($env->{PATH_INFO} eq "$prefix/metagen") {
|
||||
if (defined($env->{HTTP_REPO})) {
|
||||
($status, $content, $msg) = metagen ($env->{HTTP_REPO});
|
||||
}
|
||||
} elsif ($env->{PATH_INFO} eq "$prefix/buildinfo") {
|
||||
if (defined($env->{HTTP_REPO})) {
|
||||
($status, $content, $msg) = buildinfo ($env->{HTTP_REPO});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return [
|
||||
$status,
|
||||
[ 'Content-Type' => $content, 'Content-Length' => length $msg ],
|
||||
[ $msg ],
|
||||
];
|
||||
};
|
||||
|
||||
__END__
|
||||
# vim: set ft=perl noet ai ts=4 sw=4 sts=4:
|
||||
17
slackmetarep.yaml
Normal file
17
slackmetarep.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
uwsgi:
|
||||
http-socket: 127.0.0.1:3082
|
||||
tcp-nodelay: true
|
||||
tcp-fastopen: 64
|
||||
chdir: /var/www/slackmetarep
|
||||
plugins: psgi
|
||||
psgi: /var/www/slackmetarep/slackmetarep.psgi
|
||||
processes: 1
|
||||
enable-threads: false
|
||||
thunder-lock: true
|
||||
logformat: %(ctime) %(var.REMOTE_ADDR) %(var.REQUEST_METHOD) %(var.REQUEST_URI) %(status) %(rsize) %(msecs)
|
||||
need-app: true
|
||||
log-reopen: yes
|
||||
reload-mercy: 5
|
||||
buffer-size: 32768
|
||||
logto: /var/log/uwsgi/slackmetarep.log
|
||||
die-on-term: true
|
||||
Reference in New Issue
Block a user