Setting up your own APT repository with upload support
Posted by Steve on Sat 5 Nov 2005 at 16:04
We've previously covered setting up your own repository for the Debian's apt-get system, but we didn't cover managing automatic uploads. Thankfully this is a simple task with the reprepro, and dupload tools and a small amount of scripting.
The reprepro package is tool for creating an APT repository with a pool structure, the same type of structure the official Debian mirrors use.
The repository may:
- Contain packages for multiple distributions:
- Stable, Unstable, Testing, etc.
- Contain packages for multiple architectures:
- x86, sparc, all, etc.
- Be managed quickly and easily.
Removing PackagesInstalling the package is straightforward if you're using unstable, or etch, simply install it as you would install any other package:
apt-get install repreproUnfortunately the package contained within Debian's stable release, sarge, is a little outdated. For that reason I'd recommend that you install a back ported version. Thankfully this is readily available either from the projects homepage or elsewhere:
Once you've installed the software then we're ready to begin creating a repository. A new repository can be created in just a couple of steps:
- Decide where you wish the archive to be located.
- Create the configuration file.
- Import your first package
Almost certainly you will wish to serve your repository via a webserver, so the location should be beneath your webservers root directory at a simple path.
I use http://steve.org.uk/apt as my repository root location so my archive will be located beneath /home/www/www.steve.org.uk/htdocs/apt - your location will obviously differ.
First of all create the directory, a subdirectory conf/ to contain the configuration file, and a directory incoming/ to which we'll later setup automatic upload processing:
mkdir -p /home/www/www.steve.org.uk/htdocs/apt mkdir -p /home/www/www.steve.org.uk/htdocs/apt/conf mkdir -p /home/www/www.steve.org.uk/htdocs/apt/incomingNow that we have a directory to contain our repository we can look at creating the configuration file. The configuration file will specify which releases the repository will contain (sid, stable, etc) as well as the architectures. A sample configuration file will look like this:
Origin: Your Name Label: Your own label Suite: stable Codename: sarge Version: 3.1 Architectures: i386 all source Components: main non-free contrib Description: Your descriptionHere we've defined a repository which only contains packages for stable/sarge, which contains packages targeted to x86, or all. If you wish to contain both stable and unstable packages your configuration file will look like this:
Origin: Your Name Label: Your own label Suite: stable Codename: sarge Version: 3.1 Architectures: i386 all source Components: main non-free contrib Description: Your description Origin: Your Name Label: Your own label Suite: unstable Codename: sid Architectures: i386 all source Components: main non-free contrib Description: Your descriptionSave your configuration to the file conf/distributions and you should now be ready to import a package.
You can either import a .deb file into the repository, or a .changes file which is produced by building a package from source.
From the main directory run:
reprepro -Vb . include sarge name_of_fileFor example:
skx@lappy:~/apt$ reprepro -Vb . include sarge \ /home/skx/debian/sarge/reprepro/reprepro_0.6-1sarge0_i386.changes Created directory "./db" Created directory "./pool" Created directory "./pool/main" Created directory "./pool/main/r" Created directory "./pool/main/r/reprepro" db: 'reprepro' added to 'sarge|main|i386'. db: 'reprepro' added to 'sarge|main|source'. Created directory "./dists" Created directory "./dists/sarge" Created directory "./dists/sarge/main" Created directory "./dists/sarge/main/binary-i386" writing to './dists/sarge/main/binary-i386/Packages.new'... writing to './dists/sarge/main/binary-i386/Packages.gz.new'... Created directory "./dists/sarge/main/binary-all" writing to './dists/sarge/main/binary-all/Packages.new'... writing to './dists/sarge/main/binary-all/Packages.gz.new'... Created directory "./dists/sarge/main/source" writing to './dists/sarge/main/source/Sources.gz.new'... Created directory "./dists/sarge/non-free" Created directory "./dists/sarge/non-free/binary-i386" writing to './dists/sarge/non-free/binary-i386/Packages.new'... writing to './dists/sarge/non-free/binary-i386/Packages.gz.new'... Created directory "./dists/sarge/non-free/binary-all" writing to './dists/sarge/non-free/binary-all/Packages.new'... writing to './dists/sarge/non-free/binary-all/Packages.gz.new'... Created directory "./dists/sarge/non-free/source" writing to './dists/sarge/non-free/source/Sources.gz.new'... Created directory "./dists/sarge/contrib" Created directory "./dists/sarge/contrib/binary-i386" writing to './dists/sarge/contrib/binary-i386/Packages.new'... writing to './dists/sarge/contrib/binary-i386/Packages.gz.new'... Created directory "./dists/sarge/contrib/binary-all" writing to './dists/sarge/contrib/binary-all/Packages.new'... writing to './dists/sarge/contrib/binary-all/Packages.gz.new'... Created directory "./dists/sarge/contrib/source" writing to './dists/sarge/contrib/source/Sources.gz.new'...This has imported the package described in the file reprepro_0.6-1sarge0_i386.changes to the archive, creating the appropriate directories as required.
To have a less verbose output simply omit the -V flag, thusly:
skx@lappy:~/apt$ reprepro -b . include sarge \ /home/skx/debian/sarge/reprepro/reprepro_0.6-1sarge0_i386.changes skx@lappy:~/apt$
Using Your RepositoryIf you wish to remove a package from your repository you can do so with the remove command:
skx@lappy:~/apt$ reprepro -b . remove sarge reprepro Deleting files no longer referenced... deleting and forgetting pool/main/r/reprepro/reprepro_0.6-1sarge0_i386.deb deleting and forgetting pool/main/r/reprepro/reprepro_0.6-1sarge0.dsc deleting and forgetting pool/main/r/reprepro/reprepro_0.6.orig.tar.gz deleting and forgetting pool/main/r/reprepro/reprepro_0.6-1sarge0.diff.gzNote: you don't need to remove a package if you simply wish to replace an existing package with a newer version - this will be handled for you. When you import a newer version of a package contained in the archive already the older version will be removed.
Configuring Package Uploads With duploadOnce your packages has been added to the archive they may be downloaded via apt-get, or aptitude, with the appropriate lines in your /etc/apt/sources.list file:
deb http://example.com/apt sarge main contrib non-free deb-src http://example.com/apt sarge main contrib non-freeIf you're using two distributions simply repeat for each:
deb http://example.com/apt sarge main contrib non-free deb-src http://example.com/apt sarge main contrib non-free deb http://example.com/apt sid main contrib non-free deb-src http://example.com/apt sid main contrib non-freeYou should find that packages can be downloaded and installed as expected.
Importing Packages from an Incoming queue with repreprodupload is a tool which is designed to allow you to upload packages to different repositories.
Once installed (via "apt-get install dupload") it may be configured either via the file /etc/dupload.conf or ~/.dupload.conf.
To configure uploads for your remote host then simply add a section such as this:
$cfg{'example'} = { fqdn => "example.com", login => "steve", method => "scpb", incoming => "/incoming/", # The dinstall on ftp-master sends emails itself dinstall_runs => 1, };This configuration :
- Names the upload target 'example'.
- Specifies that file uploads should be conducted using scp.
- With the login name steve.
- That packages should be uploaded into the directory /incoming.
You will certainly need to change the hostname, login name, and incoming directory. You might also wish to specify an alternative means of uploading, such as anonymous FTP. For more details of the available options please see "man dupload.conf".
Once you've configured the upload settings you should be able to upload a Debian package by executing:
dupload --to example \ /home/skx/debian/sarge/reprepro/reprepro_0.6-1sarge0_i386.changes(Note that you should upload the .changes file, not the .deb file)
Once this command completes you'll find that you've successfully transferred the package to your incoming directory, beneath your apt root.
The next step is to allow reprepro to automatically add that package to the repository.
As a result of any dupload commands we'll expect to process the incoming files from the incoming/ directory. We've already seen that reprepro can handle the importing of packages via the .changes file.
So we simply need to write a small shell script which will locate each .changes file, import the package, then clean the directory afterwards.
(We must remove, or move, the files from the incoming directory to make sure we don't repeatedly try to re-add the same package.)
This is a sample script which does the job. It is based upon the one I use myself and should be easily usable elsewhere - simply change the incoming directory at the top of the script:
#!/bin/sh INCOMING=/home/www/www.steve.org.uk/htdocs/apt/incoming # # Make sure we're in the apt/ directory # cd $INCOMING cd .. # # See if we found any new packages # found=0 for i in $INCOMING/*.changes; do if [ -e $i ]; then found=`expr $found + 1` fi done # # If we found none then exit # if [ "$found" -lt 1 ]; then exit fi # # Now import each new package that we *did* find # for i in $INCOMING/*.changes; do # Import package to 'sarge' distribution. reprepro -Vb . include sarge $i # Delete the referenced files sed '1,/Files:/d' $i | sed '/BEGIN PGP SIGNATURE/,$d' \ | while read MD SIZE SECTION PRIORITY NAME; do if [ -z "$NAME" ]; then continue fi # # Delete the referenced file # if [ -f "$INCOMING/$NAME" ]; then rm "$INCOMING/$NAME" || exit 1 fi done # Finally delete the .changes file itself. rm $i doneTo use this simply setup a cronjob running every few minutes to process any new files in the incoming/ directory - something like this:
*/5 * * * * /usr/local/bin/import-new-packages.sh
How do you operate for unattended gpg signing? Is gnupg-agent the only option?
Regarding the script, I would parse the changes file to catch the right distribution (if you have one incoming directory for several distributions):
- reprepro -Vb . include sarge $i + DISTRIBUTION=$(cat $i | grep '^Distribution: ' | sed 's/Distribution: //') + reprepro -Vb . include $DISTRIBUTION $i
However, to use this, you have to invert "codename" and "suite" fields in the conf/distributions file.
I think the last bit is a typo from an adaptation:
- rm "$INCOMING/$NAME" "$DESTINATION" || exit 1 + rm "$INCOMING/$NAME" || exit 1
Cheers,
Julien
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Good catch on the rm problem - in my script rather than deleting the files I move them into an accepted/ directory - which is why there was a second argument left in there.
The idea of getting the distribution from the .changes file is a good one too - I honestly didn't think of that, but I guess you'd need to do that if you had more than one distribution available.
I'll leave that out of the script, since it might confuse people - but it will be available as a comment :)
Steve
--
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Oops I forgot about your question!
gnupg-agent appears to be the only option, yes. I've not explored anything else, other than making .bz2 indexes available.
Steve
--
[ Parent | Reply to this comment ]
Thanks
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
I'm not sure. Right now I just have this in conf/distributions:
SignWith: apt@steve.org.uk
And it all works because my key is explicitly for that, and has no passphrase.
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
Cheers, Julien
[ Parent | Reply to this comment ]
Or is some more common way?
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
One small problem, though: I had to change the first line of dupload.conf to
$config::cfg{'example'} = {
since that's what dupload requires.
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
[ Parent | Reply to this comment ]
reprepro -Vb . includedeb sarge your_package.deb
('includedeb' instead of 'include')
Otherwise it will fail to add your package. HTH.
--sithender
[ Parent | Reply to this comment ]
Was trying create a small repository with some old packages needed by another old program that we are using. I setup the repository etc. and tried adding in the package gtkscintilla_0.8.2-1_i386.deb. I can install the pacakge fine with the dpkg -i command but when I try to add in the package using the command
"reprepro -V -C contrib -A i386 includedeb etch gtkscintilla_0.8.2-1_i386.deb"
I get the following messages
tar: ./control: Not found in archive
tar: Error exit delayed from previous errors
Got no control information from .deb!
Error from tar: 2
There have been errors!
and the package is not added to the repository. Any ideas?
The package is available at http://www.muriquilinux.com.br/debian/pool/struct/php-gtk/gtkscin tilla_0.8.2-1_i386.deb
Thanks
[ Parent | Reply to this comment ]
Steve, your loop that increments (and checks for the value of) $found is not necessary.
for f in *some_file_filter*; do # this will only be run if $f actually holds a value now do the actual processing... done
You can simply remove this part:
#
# See if we found any new packages
#
found=0
for i in $INCOMING/*.changes; do
if [ -e $i ]; then
found=`expr $found + 1`
fi
done
#
# If we found none then exit
#
if [ "$found" -lt 1 ]; then
exit
fi/peter
[ Parent | Reply to this comment ]
for f in *some_file_filter*; do # this will only be run if $f actually holds a value now do the actual processing... doneyou should do this:
for f in *some_file_filter*; do # if nothing matches the filter, the shell will return the filter string test -e "$f" || continue # this will only be run if $f actually holds a value now do the actual processing... doneTo witness this, issue this command:
echo *there_is_no_match*
[ Parent | Reply to this comment ]
I am curious as to how to handle more than one architecture. That is, I have both i386 and amd64 machines that I use and I would like to make the packages available for both architectures. I have a pbuilder running on an i386 machine and another on an amd64 machine. Can I just build them independently (say on the amd64 first) and then add the line for foo_0.0.0-0_i386.deb manually to the .changes file? Otherwise, I am thinking that reprepro won't know what to do if I hand it a .changes that only mentions one .deb along with two .debs.
Any ideas would be greatly appreciated. BTW, this is pretty nifty as it has made me reconsider my old manual approach (remember the article I submitted over a year ago now)? :-)
--
Roberto C. Sanchez
http://familiasanchez.net/~roberto
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Hmmm that is an interesting question.
I suspect you could build the package twice using the same orig.tar.gz, and a different .deb + changes for each and upload both. Since the .deb files would have different archs and the same version I think it would work out OK.
Here I think it would work because you can either import the .changes file or the .deb file. So import the .changes file for the x86 package - then afterwards import the x64 .deb file
Failing that hacking the .changes files manually to include both binary packages would presumably work, but would be more of a pain to apply since you'd need to resign the .changes file.
I guess the best thing to do is to try it and see!
[ Parent | Reply to this comment ]
Make a distribution with
Architecture: i386 amd64 source
then build your package on on of the architectures, for examples i386
with dpkg-buildpackage (if it is not ending with -0 or -1 and you do no
have the .orig.tar.gz already in the pool add a -sa to dpkg-buildpackage
so the changes file includes the .orig.tar.gz) and add that .changes
file to reprepro.
Then build the package on the other architecture, for example amd64
with the -B (upper case B) option, this will dpkg-buildpackage tell
to only generate the architecture specific packages, thus it will
create a .changes file only including _amd64.deb files. Then simply
tell reprepro to include this .changes file.
[ Parent | Reply to this comment ]
Architecture-all packages are included in all architectures, especially in that
architecture "all", so Architecture: all packages are actually ending up there.
This is a bug in reprepro, that it handles "all" special, why not disallowing
architectures called this way. Adding packages works (to my supprise), but I am not sure if everything else will work. I strongly discourage it.
To get rid of it, remvoe the all from the Archtecture line and manually
remove the binary-all directories from your distdir. (reprepro does not yet
have any support for removing Packages files not longer needed)
[ Parent | Reply to this comment ]
[ Send Message | View dkg's Scratchpad | View Weblogs ]
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
I don't often fix such changes retroactively, since they were correct at the time the article was written..
The comments should be sufficient to help people learn :)Steve
[ Parent | Reply to this comment ]
Does anyone have an idea how to move packages from one "component" to another using reprepro, for example from main to non-free ?
Thanks.
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Remove it from its old location. Rebuild with the correct section in the control file and re-upload?
[ Parent | Reply to this comment ]
I've a local partial mirror made with debmirror, and I want add my own packages into it. I've tried reprepro, but it recreate Packages(.gz and .bz2 too), with only new added packages, ignoring others in pool.
Is possible for reprepro to read the full pool and only update Packages file?
thanks a lot
[ Parent | Reply to this comment ]
What about upload of an .orig.tar.gz file? The .changes file doesn't know
about it.
I would like to upload to my own repository a .deb file and full Debian
source package (.dsc, .orig.tar.gz and .diff.gz files).
What tool should I use to upload an .orig.tar.gz file? Where should I
put that file? Is incoming direcory good place?
P.
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
It'll work just fine if you've uploaded the first revision of a package built with "-sa". (Since in that case the .orig.tar.gz file will be mentioned in the .changes file.)
For subsequent uploads don't include it as it will be already present.
[ Parent | Reply to this comment ]
uploaded only .orig.tar.gz file :)
Thank you very much! You have a beer from me if I will be near
Edinburgh someday ;)
P.
[ Parent | Reply to this comment ]
[ Send Message | View Steve's Scratchpad | View Weblogs ]
Well there is always Debconf next year which will be held here!
[ Parent | Reply to this comment ]
- Josh Triplett
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
When there's a new release of Debian, you may want to do a couple of things:
* edit conf/distributions, and
** add a set of lines for the new distribution
** update the Suite: lines, eg "stable" changes to "oldstable"
* reprepro -Vb . export # to update Packages and Release files
* reprepro -Vb . createsymlinks # to update symlinks, e.g. oldstable->etch
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]
[ Parent | Reply to this comment ]