Increase version to 0.10.0
[Fedora-Rebuild.git] / lib / Fedora / Rebuild / Repository.pm
blob4dfd15c002e1c33b831ab01c9be005078556d8f6
1 package Fedora::Rebuild::Repository;
2 use strict;
3 use warnings;
4 use version 0.77; our $VERSION = version->declare("v0.10.0");
6 use threads;
7 use threads::shared;
8 use Moose;
9 use Carp;
10 use File::Path;
11 use File::Spec;
12 use HTTP::Daemon;
13 use HTTP::Status qw(:constants :is status_message);
14 use Fedora::Rebuild::Execute;
15 use namespace::clean;
17 # Directory where the repository exists
18 has 'path' => ( is => 'ro', isa => 'Str', required => 1);
20 # Private attributes
21 has 'pid' => ( is => 'rw', isa => 'Int', lazy=> 1, init_arg => undef,
22 default => 0);
23 has 'url' => ( is => 'rw', isa => 'Maybe[Str]', lazy=> 1, init_arg => undef,
24 default => undef);
26 around BUILDARGS => sub {
27 my $orig = shift;
28 my $class = shift;
29 my %attrs = @_;
31 if (! defined $attrs{'path'} || $attrs{'path'} eq '') {
32 croak "Path must be a non-empty string";
35 $attrs{'path'} = File::Spec->rel2abs($attrs{'path'});
36 if (! -d $attrs{'path'}) {
37 File::Path::make_path($attrs{'path'}) or
38 croak("Could not create repository directory `". $attrs{'path'} .
39 "': $!\n");
42 return $class->$orig(%attrs);
45 # Make object shared between threads to prevent killing daemon by DEMOLISH
46 # from scheduler threads.
47 # XXX: No attributes are shared automatically.
48 around 'new' => sub {
49 my $orig = shift;
50 my $class = shift;
51 return shared_clone($class->$orig(@_));
54 # Kill the server process on object desctruction
55 sub DEMOLISH {
56 shift->stop;
59 # Insert binary RPM files built from the package, the argument, into
60 # repository. It will not update the YUM metatada. You need to update the
61 # reporitoty explicitly.
62 # Croaks on failure.
63 sub insert {
64 my ($self, $package) = @_;
65 for my $file ($package->listbinaryrpmfiles) {
66 my ($volume, $prefix, $file_name) = File::Spec->splitpath($file);
67 my $link = File::Spec->catfile($self->path, $file_name);
68 my $target = File::Spec->abs2rel($file, $self->path);
69 if (-l $link or -e $link) {
70 unlink $link or croak("Could not remove old `" . $link .
71 "': $!\n");
73 if (!symlink($target, $link)) {
74 croak("Could not insert RPM file `" . $file . "' of package `" .
75 $package->name . "' into `" . $self->path . "': $!\n");
78 return 1;
81 # Update the repository.
82 # This updates YUM metadata.
83 sub update {
84 my $self = shift;
85 print "Updating YUM repository of already rebuilt packages...\n";
86 if (!Fedora::Rebuild::Execute->new->do(
87 $self->path, 'createrepo', '--update', '.')) {
88 croak("Could not update repository.\n");
90 print "Repository updated successufully.\n";
91 return 1;
95 # Start to serve the repository over HTTP.
96 # Return URL. undef in case of error.
97 sub start {
98 my ($self) = @_;
100 if ($self->pid && kill(0, $self->pid)) {
101 # Server is already running
102 return $self->url;
105 # Start new server
106 $self->pid(0);
107 $self->url(undef);
108 my $server = HTTP::Daemon->new( 'LocalAddr' => 'localhost' );
109 if (!defined($server)) {
110 return undef;
112 my $daemon = fork;
113 if (!defined $daemon) {
114 # Fork failed
115 undef $server;
116 return undef;
117 } elsif ($daemon == 0) {
118 # Daemon
119 $self->run_daemon($server);
120 exit 0;
121 } else {
122 # Parent
123 $self->pid($daemon);
124 $self->url($server->url);
125 return $self->url;
130 # Stop serving the repository
131 sub stop {
132 my $self = shift;
133 if ($self->pid) {
134 kill 9, $self->pid;
135 waitpid($self->pid, 0);
136 $self->pid(0);
141 # Private method
142 sub run_daemon {
143 my ($self, $server) = @_;
144 if (! defined $server) { return -1; }
146 my $connection;
147 while (1) {
148 if (defined $connection) {
149 $connection->close;
150 undef($connection);
153 $connection = $server->accept;
154 my $request = $connection->get_request;
155 $connection->force_last_request;
157 if (! defined $request) {
158 print STDERR "repository server: Bad request\n";
159 next;
161 if ($request->method eq 'GET') {
162 my $rpath = $request->uri;
163 if ($rpath =~ m|\.\./|) {
164 $connection->send_error(HTTP_FORBIDDEN,
165 "Parent directories are fobidden");
166 next;
168 $rpath =~ s|^/||;
169 $connection->send_file_response(
170 File::Spec->catfile($self->path, $rpath));
171 } else {
172 $connection->send_error(HTTP_NOT_IMPLEMENTED,
173 "Only GET method is supported");