]> git.ipfire.org Git - pakfire.git/commitdiff
Add experimental support for package signatures.
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 11 Feb 2012 12:01:56 +0000 (13:01 +0100)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 11 Feb 2012 12:01:56 +0000 (13:01 +0100)
12 files changed:
po/pakfire.pot
python/pakfire/api.py
python/pakfire/base.py
python/pakfire/cli.py
python/pakfire/constants.py
python/pakfire/keyring.py [new file with mode: 0644]
python/pakfire/packages/__init__.py
python/pakfire/packages/file.py
python/pakfire/repository/index.py
python/pakfire/repository/local.py
tools/Makefile
tools/pakfire-multicall.py

index 58419eb633e887ae9dac0dc2f393404d2d14dc19..5bac065ff8a4c1bb6fcd1c41ea41e12c8015fa71 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-01-26 22:46+0100\n"
+"POT-Creation-Date: 2012-02-11 12:47+0100\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -74,520 +74,629 @@ msgstr ""
 msgid "Downgrading"
 msgstr ""
 
-#: ../python/pakfire/base.py:211 ../python/pakfire/base.py:241
-#: ../python/pakfire/base.py:287 ../python/pakfire/base.py:338
-#: ../python/pakfire/base.py:404 ../python/pakfire/base.py:441
-#: ../python/pakfire/base.py:494 ../python/pakfire/base.py:514
+#: ../python/pakfire/base.py:214 ../python/pakfire/base.py:244
+#: ../python/pakfire/base.py:290 ../python/pakfire/base.py:341
+#: ../python/pakfire/base.py:407 ../python/pakfire/base.py:444
+#: ../python/pakfire/base.py:497 ../python/pakfire/base.py:517
 msgid "Nothing to do"
 msgstr ""
 
-#: ../python/pakfire/base.py:273
+#: ../python/pakfire/base.py:276
 msgid "There are no packages to install."
 msgstr ""
 
-#: ../python/pakfire/base.py:328
+#: ../python/pakfire/base.py:331
 #, python-format
 msgid "Could not find any installed package providing \"%s\"."
 msgstr ""
 
-#: ../python/pakfire/base.py:334
+#: ../python/pakfire/base.py:337
 #, python-format
 msgid "Multiple reinstall candidates for \"%s\": %s"
 msgstr ""
 
-#: ../python/pakfire/base.py:363
+#: ../python/pakfire/base.py:366
 #, python-format
 msgid "Could not find package %s in a remote repository."
 msgstr ""
 
-#: ../python/pakfire/base.py:432
+#: ../python/pakfire/base.py:435
 #, python-format
 msgid "Excluding %s."
 msgstr ""
 
-#: ../python/pakfire/base.py:482
+#: ../python/pakfire/base.py:485
 #, python-format
 msgid "\"%s\" package does not seem to be installed."
 msgstr ""
 
-#: ../python/pakfire/base.py:626
+#: ../python/pakfire/base.py:629
 msgid "Build command has failed."
 msgstr ""
 
-#: ../python/pakfire/base.py:706
+#: ../python/pakfire/base.py:713
 msgid "Everything is fine."
 msgstr ""
 
+#: ../python/pakfire/builder.py:128
+#, python-format
+msgid "Cannot build for %s on this host."
+msgstr ""
+
 #. Log the package information.
-#: ../python/pakfire/builder.py:155
+#: ../python/pakfire/builder.py:159
 msgid "Package information:"
 msgstr ""
 
 #. Install all packages.
-#: ../python/pakfire/builder.py:326
+#: ../python/pakfire/builder.py:330
 msgid "Install packages needed for build..."
 msgstr ""
 
-#: ../python/pakfire/builder.py:331
+#: ../python/pakfire/builder.py:335
 msgid "Extracting"
 msgstr ""
 
-#: ../python/pakfire/builder.py:600
+#: ../python/pakfire/builder.py:604
 msgid "You cannot run a build when no package was given."
 msgstr ""
 
-#: ../python/pakfire/builder.py:605
+#: ../python/pakfire/builder.py:609
 #, python-format
 msgid "Could not find makefile in build root: %s"
 msgstr ""
 
-#: ../python/pakfire/builder.py:619
+#: ../python/pakfire/builder.py:623
 msgid "The build command failed. See logfile for details."
 msgstr ""
 
 #. Walk through the whole tree and collect all files
 #. that are on the same disk (not crossing mountpoints).
-#: ../python/pakfire/builder.py:677
+#: ../python/pakfire/builder.py:681
 msgid "Creating filelist..."
 msgstr ""
 
 #. Create a nice progressbar.
-#: ../python/pakfire/builder.py:696
+#: ../python/pakfire/builder.py:700
 msgid "Compressing files..."
 msgstr ""
 
-#: ../python/pakfire/builder.py:715
+#: ../python/pakfire/builder.py:719
 #, python-format
 msgid "Cache file was successfully created at %s."
 msgstr ""
 
-#: ../python/pakfire/builder.py:716
+#: ../python/pakfire/builder.py:720
 #, python-format
 msgid "  Containing %(files)s files, it has a size of %(size)s."
 msgstr ""
 
 #. Make a nice progress bar as always.
-#: ../python/pakfire/builder.py:727
+#: ../python/pakfire/builder.py:731
 msgid "Extracting files..."
 msgstr ""
 
 #. Update all packages.
-#: ../python/pakfire/builder.py:747
+#: ../python/pakfire/builder.py:751
 msgid "Updating packages from cache..."
 msgstr ""
 
 #. Package the result.
 #. Make all these little package from the build environment.
-#: ../python/pakfire/builder.py:875
+#: ../python/pakfire/builder.py:879
 msgid "Creating packages:"
 msgstr ""
 
 #. Execute the buildscript of this stage.
-#: ../python/pakfire/builder.py:895
+#: ../python/pakfire/builder.py:899
 #, python-format
 msgid "Running stage %s:"
 msgstr ""
 
-#: ../python/pakfire/builder.py:913
+#: ../python/pakfire/builder.py:917
 #, python-format
 msgid "Could not remove static libraries: %s"
 msgstr ""
 
-#: ../python/pakfire/builder.py:919
+#: ../python/pakfire/builder.py:923
 msgid "Compressing man pages did not complete successfully."
 msgstr ""
 
-#: ../python/pakfire/builder.py:939
+#: ../python/pakfire/builder.py:943
 msgid "Extracting debuginfo did not complete with success. Aborting build."
 msgstr ""
 
-#: ../python/pakfire/cli.py:47
+#: ../python/pakfire/cli.py:48
 msgid "Pakfire command line interface."
 msgstr ""
 
-#: ../python/pakfire/cli.py:54
+#: ../python/pakfire/cli.py:55
 msgid "The path where pakfire should operate in."
 msgstr ""
 
-#: ../python/pakfire/cli.py:121
+#: ../python/pakfire/cli.py:122
 msgid "Enable verbose output."
 msgstr ""
 
-#: ../python/pakfire/cli.py:124
+#: ../python/pakfire/cli.py:125
 msgid "Path to a configuration file to load."
 msgstr ""
 
-#: ../python/pakfire/cli.py:128
+#: ../python/pakfire/cli.py:129
 msgid "Disable a repository temporarily."
 msgstr ""
 
-#: ../python/pakfire/cli.py:131
+#: ../python/pakfire/cli.py:132
 msgid "Enable a repository temporarily."
 msgstr ""
 
-#: ../python/pakfire/cli.py:135
+#: ../python/pakfire/cli.py:136
 msgid "Run pakfire in offline mode."
 msgstr ""
 
-#: ../python/pakfire/cli.py:140
+#: ../python/pakfire/cli.py:141
 msgid "Install one or more packages to the system."
 msgstr ""
 
-#: ../python/pakfire/cli.py:142
+#: ../python/pakfire/cli.py:143
 msgid "Give name of at least one package to install."
 msgstr ""
 
-#: ../python/pakfire/cli.py:148
+#: ../python/pakfire/cli.py:149
 msgid "Install one or more packages from the filesystem."
 msgstr ""
 
-#: ../python/pakfire/cli.py:150
+#: ../python/pakfire/cli.py:151
 msgid "Give filename of at least one package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:156
+#: ../python/pakfire/cli.py:157
 msgid "Reinstall one or more packages."
 msgstr ""
 
-#: ../python/pakfire/cli.py:158
+#: ../python/pakfire/cli.py:159
 msgid "Give name of at least one package to reinstall."
 msgstr ""
 
-#: ../python/pakfire/cli.py:164
+#: ../python/pakfire/cli.py:165
 msgid "Remove one or more packages from the system."
 msgstr ""
 
-#: ../python/pakfire/cli.py:166
+#: ../python/pakfire/cli.py:167
 msgid "Give name of at least one package to remove."
 msgstr ""
 
-#: ../python/pakfire/cli.py:172
+#: ../python/pakfire/cli.py:173
 msgid "Give a name of a package to update or leave emtpy for all."
 msgstr ""
 
-#: ../python/pakfire/cli.py:174
+#: ../python/pakfire/cli.py:175
 msgid "Exclude package from update."
 msgstr ""
 
-#: ../python/pakfire/cli.py:176 ../python/pakfire/cli.py:201
+#: ../python/pakfire/cli.py:177 ../python/pakfire/cli.py:202
 msgid "Allow changing the vendor of packages."
 msgstr ""
 
-#: ../python/pakfire/cli.py:178 ../python/pakfire/cli.py:203
+#: ../python/pakfire/cli.py:179 ../python/pakfire/cli.py:204
 msgid "Allow changing the architecture of packages."
 msgstr ""
 
-#: ../python/pakfire/cli.py:183
+#: ../python/pakfire/cli.py:184
 msgid "Update the whole system or one specific package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:190
+#: ../python/pakfire/cli.py:191
 msgid "Check, if there are any updates available."
 msgstr ""
 
-#: ../python/pakfire/cli.py:197
+#: ../python/pakfire/cli.py:198
 msgid "Downgrade one or more packages."
 msgstr ""
 
-#: ../python/pakfire/cli.py:199
+#: ../python/pakfire/cli.py:200
 msgid "Give a name of a package to downgrade."
 msgstr ""
 
-#: ../python/pakfire/cli.py:209
+#: ../python/pakfire/cli.py:210
 msgid "Print some information about the given package(s)."
 msgstr ""
 
-#: ../python/pakfire/cli.py:211
+#: ../python/pakfire/cli.py:212
 msgid "Give at least the name of one package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:217
+#: ../python/pakfire/cli.py:218
 msgid "Search for a given pattern."
 msgstr ""
 
-#: ../python/pakfire/cli.py:219
+#: ../python/pakfire/cli.py:220
 msgid "A pattern to search for."
 msgstr ""
 
-#: ../python/pakfire/cli.py:225
+#: ../python/pakfire/cli.py:226
 msgid "Get a list of packages that provide a given file or feature."
 msgstr ""
 
-#: ../python/pakfire/cli.py:227
+#: ../python/pakfire/cli.py:228
 msgid "File or feature to search for."
 msgstr ""
 
-#: ../python/pakfire/cli.py:233
+#: ../python/pakfire/cli.py:234
 msgid "Get list of packages that belong to the given group."
 msgstr ""
 
-#: ../python/pakfire/cli.py:235
+#: ../python/pakfire/cli.py:236
 msgid "Group name to search for."
 msgstr ""
 
-#: ../python/pakfire/cli.py:241
+#: ../python/pakfire/cli.py:242
 msgid "Install all packages that belong to the given group."
 msgstr ""
 
-#: ../python/pakfire/cli.py:243
+#: ../python/pakfire/cli.py:244
 msgid "Group name."
 msgstr ""
 
-#: ../python/pakfire/cli.py:249
+#: ../python/pakfire/cli.py:250
 msgid "List all currently enabled repositories."
 msgstr ""
 
-#: ../python/pakfire/cli.py:253
+#: ../python/pakfire/cli.py:254
 msgid "Cleanup commands."
 msgstr ""
 
-#: ../python/pakfire/cli.py:261
+#: ../python/pakfire/cli.py:262
 msgid "Cleanup all temporary files."
 msgstr ""
 
-#: ../python/pakfire/cli.py:267
+#: ../python/pakfire/cli.py:268
 msgid "Check the system for any errors."
 msgstr ""
 
-#: ../python/pakfire/cli.py:273
+#: ../python/pakfire/cli.py:274
 msgid "Check the dependencies for a particular package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:275
+#: ../python/pakfire/cli.py:276
 msgid "Give name of at least one package to check."
 msgstr ""
 
-#: ../python/pakfire/cli.py:351 ../python/pakfire/transaction.py:352
+#: ../python/pakfire/cli.py:352 ../python/pakfire/transaction.py:352
 msgid "Repository"
 msgstr ""
 
-#: ../python/pakfire/cli.py:351
+#: ../python/pakfire/cli.py:352
 msgid "Enabled"
 msgstr ""
 
-#: ../python/pakfire/cli.py:351
+#: ../python/pakfire/cli.py:352
 msgid "Priority"
 msgstr ""
 
-#: ../python/pakfire/cli.py:351
+#: ../python/pakfire/cli.py:352
 msgid "Packages"
 msgstr ""
 
-#: ../python/pakfire/cli.py:363
+#: ../python/pakfire/cli.py:364
 msgid "Cleaning up everything..."
 msgstr ""
 
-#: ../python/pakfire/cli.py:379
+#: ../python/pakfire/cli.py:380
 msgid "You cannot run pakfire-builder in a pakfire chroot."
 msgstr ""
 
-#: ../python/pakfire/cli.py:382 ../python/pakfire/cli.py:719
+#: ../python/pakfire/cli.py:383 ../python/pakfire/cli.py:726
 msgid "Pakfire builder command line interface."
 msgstr ""
 
-#: ../python/pakfire/cli.py:440
+#: ../python/pakfire/cli.py:441
 msgid "Update the package indexes."
 msgstr ""
 
-#: ../python/pakfire/cli.py:446 ../python/pakfire/cli.py:739
+#: ../python/pakfire/cli.py:447 ../python/pakfire/cli.py:746
 msgid "Build one or more packages."
 msgstr ""
 
-#: ../python/pakfire/cli.py:448 ../python/pakfire/cli.py:633
-#: ../python/pakfire/cli.py:741
+#: ../python/pakfire/cli.py:449 ../python/pakfire/cli.py:635
+#: ../python/pakfire/cli.py:748
 msgid "Give name of at least one package to build."
 msgstr ""
 
-#: ../python/pakfire/cli.py:452 ../python/pakfire/cli.py:745
-#: ../python/pakfire/cli.py:815
+#: ../python/pakfire/cli.py:453 ../python/pakfire/cli.py:752
+#: ../python/pakfire/cli.py:822
 msgid "Build the package for the given architecture."
 msgstr ""
 
-#: ../python/pakfire/cli.py:454 ../python/pakfire/cli.py:482
-#: ../python/pakfire/cli.py:747
+#: ../python/pakfire/cli.py:455 ../python/pakfire/cli.py:483
+#: ../python/pakfire/cli.py:754
 msgid "Path were the output files should be copied to."
 msgstr ""
 
-#: ../python/pakfire/cli.py:456 ../python/pakfire/cli.py:471
-#: ../python/pakfire/cli.py:749
+#: ../python/pakfire/cli.py:457 ../python/pakfire/cli.py:472
+#: ../python/pakfire/cli.py:756
 msgid "Mode to run in. Is either 'release' or 'development' (default)."
 msgstr ""
 
-#: ../python/pakfire/cli.py:458
+#: ../python/pakfire/cli.py:459
 msgid "Run a shell after a successful build."
 msgstr ""
 
-#: ../python/pakfire/cli.py:463
+#: ../python/pakfire/cli.py:464
 msgid "Go into a shell."
 msgstr ""
 
-#: ../python/pakfire/cli.py:465
+#: ../python/pakfire/cli.py:466
 msgid "Give name of a package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:469
+#: ../python/pakfire/cli.py:470
 msgid "Emulated architecture in the shell."
 msgstr ""
 
-#: ../python/pakfire/cli.py:476
+#: ../python/pakfire/cli.py:477
 msgid "Generate a source package."
 msgstr ""
 
-#: ../python/pakfire/cli.py:478
+#: ../python/pakfire/cli.py:479
 msgid "Give name(s) of a package(s)."
 msgstr ""
 
-#: ../python/pakfire/cli.py:487
+#: ../python/pakfire/cli.py:489
 msgid "Create a build environment cache."
 msgstr ""
 
-#: ../python/pakfire/cli.py:497
+#: ../python/pakfire/cli.py:499
 msgid "Create a new build environment cache."
 msgstr ""
 
-#: ../python/pakfire/cli.py:502
+#: ../python/pakfire/cli.py:504
 msgid "Remove all cached build environments."
 msgstr ""
 
-#: ../python/pakfire/cli.py:580
+#: ../python/pakfire/cli.py:582
 #, python-format
 msgid "Removing environment cache file: %s..."
 msgstr ""
 
-#: ../python/pakfire/cli.py:586
+#: ../python/pakfire/cli.py:588
 #, python-format
 msgid "Could not remove file: %s"
 msgstr ""
 
-#: ../python/pakfire/cli.py:592
+#: ../python/pakfire/cli.py:594
 msgid "Pakfire server command line interface."
 msgstr ""
 
-#: ../python/pakfire/cli.py:631
+#: ../python/pakfire/cli.py:633
 msgid "Send a scrach build job to the server."
 msgstr ""
 
-#: ../python/pakfire/cli.py:635
+#: ../python/pakfire/cli.py:637
 msgid "Limit build to only these architecture(s)."
 msgstr ""
 
-#: ../python/pakfire/cli.py:641
+#: ../python/pakfire/cli.py:643
 msgid "Send a keepalive to the server."
 msgstr ""
 
-#: ../python/pakfire/cli.py:648
+#: ../python/pakfire/cli.py:650
 msgid "Update all repositories."
 msgstr ""
 
-#: ../python/pakfire/cli.py:654
+#: ../python/pakfire/cli.py:656
 msgid "Repository management commands."
 msgstr ""
 
-#: ../python/pakfire/cli.py:662
+#: ../python/pakfire/cli.py:664
 msgid "Create a new repository index."
 msgstr ""
 
-#: ../python/pakfire/cli.py:663
+#: ../python/pakfire/cli.py:666
 msgid "Path to the packages."
 msgstr ""
 
-#: ../python/pakfire/cli.py:664
+#: ../python/pakfire/cli.py:668
 msgid "Path to input packages."
 msgstr ""
 
-#: ../python/pakfire/cli.py:669
+#: ../python/pakfire/cli.py:670
+msgid "Key to sign the repository with."
+msgstr ""
+
+#: ../python/pakfire/cli.py:675
 msgid "Dump some information about this machine."
 msgstr ""
 
-#: ../python/pakfire/cli.py:751
+#: ../python/pakfire/cli.py:758
 msgid "Do not verify build dependencies."
 msgstr ""
 
-#: ../python/pakfire/cli.py:775
+#: ../python/pakfire/cli.py:782
 msgid "Pakfire client command line interface."
 msgstr ""
 
-#: ../python/pakfire/cli.py:809
+#: ../python/pakfire/cli.py:816
 msgid "Build a package remotely."
 msgstr ""
 
-#: ../python/pakfire/cli.py:811
+#: ../python/pakfire/cli.py:818
 msgid "Give name of a package to build."
 msgstr ""
 
-#: ../python/pakfire/cli.py:820
+#: ../python/pakfire/cli.py:827
 msgid "Print some information about this host."
 msgstr ""
 
-#: ../python/pakfire/cli.py:826
+#: ../python/pakfire/cli.py:833
 msgid "Check the connection to the hub."
 msgstr ""
 
-#: ../python/pakfire/cli.py:853 ../python/pakfire/server.py:302
+#: ../python/pakfire/cli.py:860 ../python/pakfire/server.py:302
 msgid "Hostname"
 msgstr ""
 
-#: ../python/pakfire/cli.py:854
+#: ../python/pakfire/cli.py:861
 msgid "Pakfire hub"
 msgstr ""
 
-#: ../python/pakfire/cli.py:857
+#: ../python/pakfire/cli.py:864
 msgid "Username"
 msgstr ""
 
 #. Hardware information
-#: ../python/pakfire/cli.py:861 ../python/pakfire/server.py:306
+#: ../python/pakfire/cli.py:868 ../python/pakfire/server.py:306
 msgid "Hardware information"
 msgstr ""
 
-#: ../python/pakfire/cli.py:862 ../python/pakfire/server.py:307
+#: ../python/pakfire/cli.py:869 ../python/pakfire/server.py:307
 msgid "CPU model"
 msgstr ""
 
-#: ../python/pakfire/cli.py:863 ../python/pakfire/server.py:308
+#: ../python/pakfire/cli.py:870 ../python/pakfire/server.py:308
 msgid "Memory"
 msgstr ""
 
-#: ../python/pakfire/cli.py:865 ../python/pakfire/server.py:310
+#: ../python/pakfire/cli.py:872 ../python/pakfire/server.py:310
 msgid "Native arch"
 msgstr ""
 
-#: ../python/pakfire/cli.py:867 ../python/pakfire/server.py:312
+#: ../python/pakfire/cli.py:874
+msgid "Default arch"
+msgstr ""
+
+#: ../python/pakfire/cli.py:876 ../python/pakfire/server.py:312
 msgid "Supported arches"
 msgstr ""
 
-#: ../python/pakfire/cli.py:880
+#: ../python/pakfire/cli.py:889
 msgid "Your IP address"
 msgstr ""
 
-#: ../python/pakfire/cli.py:885
+#: ../python/pakfire/cli.py:894
 msgid "You are authenticated to the build service:"
 msgstr ""
 
-#: ../python/pakfire/cli.py:891
+#: ../python/pakfire/cli.py:900
 msgid "User name"
 msgstr ""
 
-#: ../python/pakfire/cli.py:892
+#: ../python/pakfire/cli.py:901
 msgid "Real name"
 msgstr ""
 
-#: ../python/pakfire/cli.py:893
+#: ../python/pakfire/cli.py:902
 msgid "Email address"
 msgstr ""
 
-#: ../python/pakfire/cli.py:894
+#: ../python/pakfire/cli.py:903
 msgid "Registered"
 msgstr ""
 
-#: ../python/pakfire/cli.py:901
+#: ../python/pakfire/cli.py:910
 msgid "You could not be authenticated to the build service."
 msgstr ""
 
-#: ../python/pakfire/cli.py:910
+#: ../python/pakfire/cli.py:919
 msgid "Pakfire daemon command line interface."
 msgstr ""
 
+#: ../python/pakfire/cli.py:952
+msgid "Pakfire key command line interface."
+msgstr ""
+
+#: ../python/pakfire/cli.py:996
+msgid "Initialize the local keyring."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1002 ../python/pakfire/cli.py:1012
+msgid "Import a key from file."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1004
+msgid "The real name of the owner of this key."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1006
+msgid "The email address of the owner of this key."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1014
+msgid "Filename of that key to import."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1020
+msgid "Export a key to a file."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1022
+msgid "The ID of the key to export."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1024
+msgid "Write the key to this file."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1030
+msgid "List all imported keys."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1036
+msgid "Sign one or more packages."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1038
+msgid "Key that is used sign the package(s)."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1040
+msgid "Package(s) to sign."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1046
+msgid "Verify one or more packages."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1050
+msgid "Package(s) to verify."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1061
+msgid "Generating the key may take a moment..."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1108
+#, python-format
+msgid "Signing %s..."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1125
+#, python-format
+msgid "Verifying %s..."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1135
+msgid "This signature is valid."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1138
+msgid "Unknown key"
+msgstr ""
+
+#: ../python/pakfire/cli.py:1139
+msgid "Could not check if this signature is valid."
+msgstr ""
+
+#: ../python/pakfire/cli.py:1142 ../python/pakfire/keyring.py:94
+#, python-format
+msgid "Created: %s"
+msgstr ""
+
+#: ../python/pakfire/cli.py:1146 ../python/pakfire/keyring.py:97
+#, python-format
+msgid "Expires: %s"
+msgstr ""
+
 #: ../python/pakfire/client/transport.py:55
 #, python-format
 msgid "Socket error: %s"
@@ -662,6 +771,37 @@ msgstr ""
 msgid "%(commas)s and %(last)s"
 msgstr ""
 
+#: ../python/pakfire/keyring.py:67
+msgid "Initializing local keyring..."
+msgstr ""
+
+#: ../python/pakfire/keyring.py:82
+#, python-format
+msgid "Fingerprint: %s"
+msgstr ""
+
+#: ../python/pakfire/keyring.py:86
+#, python-format
+msgid "Subkey: %s"
+msgstr ""
+
+#: ../python/pakfire/keyring.py:88
+msgid "This key has expired!"
+msgstr ""
+
+#: ../python/pakfire/keyring.py:91
+msgid "This is a secret key."
+msgstr ""
+
+#: ../python/pakfire/keyring.py:99
+msgid "This key does not expire."
+msgstr ""
+
+#: ../python/pakfire/keyring.py:146
+#, python-format
+msgid "Successfully import key %s."
+msgstr ""
+
 #: ../python/pakfire/packages/base.py:99
 msgid "Name"
 msgstr ""
@@ -801,15 +941,15 @@ msgstr ""
 msgid "Searching for automatic dependencies for %s..."
 msgstr ""
 
-#: ../python/pakfire/packages/make.py:463
+#: ../python/pakfire/packages/make.py:464
 #, python-format
 msgid "Regular experession is invalid and has been skipped: %s"
 msgstr ""
 
 #. Let the user know what has been done.
-#: ../python/pakfire/packages/make.py:479
+#: ../python/pakfire/packages/make.py:480
 #, python-format
-msgid "Filter %s filtered %s."
+msgid "Filter '%s' filtered %s."
 msgstr ""
 
 #. Load progressbar.
@@ -836,31 +976,36 @@ msgstr ""
 msgid "Migrating database from format %s to %s."
 msgstr ""
 
-#: ../python/pakfire/repository/index.py:237
+#: ../python/pakfire/repository/index.py:234
 #, python-format
 msgid ""
 "I cannot be forced to re-download the metadata for the repository '%s' when "
 "running in offline mode."
 msgstr ""
 
-#: ../python/pakfire/repository/index.py:287
+#: ../python/pakfire/repository/index.py:284
 #, python-format
 msgid "%s: package database"
 msgstr ""
 
 #. Create progress bar.
-#: ../python/pakfire/repository/index.py:395
+#: ../python/pakfire/repository/index.py:392
 #, python-format
 msgid "Loading from %s"
 msgstr ""
 
 #. Add all packages from the database to the index.
-#: ../python/pakfire/repository/index.py:458
+#: ../python/pakfire/repository/index.py:455
 msgid "Loading installed packages"
 msgstr ""
 
+#. Create progressbar.
+#: ../python/pakfire/repository/local.py:104
+msgid "Signing packages..."
+msgstr ""
+
 #. Make a nice progress bar.
-#: ../python/pakfire/repository/local.py:149
+#: ../python/pakfire/repository/local.py:163
 msgid "Compressing database..."
 msgstr ""
 
@@ -899,7 +1044,7 @@ msgstr ""
 msgid "    Solutions:"
 msgstr ""
 
-#: ../python/pakfire/server.py:278 ../python/pakfire/system.py:114
+#: ../python/pakfire/server.py:278 ../python/pakfire/system.py:125
 msgid "Could not be determined"
 msgstr ""
 
@@ -997,16 +1142,16 @@ msgstr ""
 msgid "%s [y/N]"
 msgstr ""
 
-#: ../python/pakfire/util.py:254
+#: ../python/pakfire/util.py:260
 msgid "Killing orphans..."
 msgstr ""
 
-#: ../python/pakfire/util.py:261
+#: ../python/pakfire/util.py:267
 #, python-format
 msgid "Process ID %s is still running in chroot. Killing..."
 msgstr ""
 
-#: ../python/pakfire/util.py:273
+#: ../python/pakfire/util.py:279
 msgid "Waiting for processes to terminate..."
 msgstr ""
 
@@ -1195,14 +1340,14 @@ msgstr ""
 msgid "The error that lead to this:"
 msgstr ""
 
-#: ../tools/pakfire-multicall.py:69
+#: ../tools/pakfire-multicall.py:70
 msgid "An error has occured when running Pakfire."
 msgstr ""
 
-#: ../tools/pakfire-multicall.py:72
+#: ../tools/pakfire-multicall.py:73
 msgid "Error message:"
 msgstr ""
 
-#: ../tools/pakfire-multicall.py:76
+#: ../tools/pakfire-multicall.py:77
 msgid "Further description:"
 msgstr ""
index c8bff043f3e03afb8c35e809e9b0b9b52138cbaa..87886ca2e1a82bf51b6ae0fa7491178afb2b6b89 100644 (file)
@@ -113,10 +113,10 @@ def requires(patterns, **pakfire_args):
 
        return pakfire.requires(requires)
 
-def repo_create(path, input_paths, type="binary", **pakfire_args):
+def repo_create(path, input_paths, key_id=None, type="binary", **pakfire_args):
        pakfire = Pakfire(**pakfire_args)
 
-       return pakfire.repo_create(path, input_paths, type=type)
+       return pakfire.repo_create(path, input_paths, key_id=key_id, type=type)
 
 def repo_list(**pakfire_args):
        pakfire = Pakfire(**pakfire_args)
@@ -136,3 +136,31 @@ def check(**pakfire_args):
 # Cache functions
 def cache_create(**pakfire_args):
        return Pakfire.cache_create(**pakfire_args)
+
+
+# Key functions.
+
+def key_init(**pakfire_args):
+       pakfire = Pakfire(**pakfire_args)
+
+       return pakfire.keyring.init()
+
+def key_generate(realname, email, **pakfire_args):
+       pakfire = Pakfire(**pakfire_args)
+
+       return pakfire.keyring.gen_key(realname, email)
+
+def key_import(keyfile, **pakfire_args):
+       pakfire = Pakfire(**pakfire_args)
+
+       return pakfire.keyring.import_key(keyfile)
+
+def key_export(keyid, keyfile, **pakfire_args):
+       pakfire = Pakfire(**pakfire_args)
+
+       return pakfire.keyring.export_key(keyid, keyfile)
+
+def key_list(**pakfire_args):
+       pakfire = Pakfire(**pakfire_args)
+
+       return pakfire.keyring.list_keys()
index 47d3c1c1e950374eb49e7e880bd6dc032c5b32a1..95104174675f67e029d61cc5ca499d8eaa5de220 100644 (file)
@@ -28,6 +28,7 @@ import builder
 import config
 import distro
 import filelist
+import keyring
 import logger
 import packages
 import repository
@@ -85,6 +86,9 @@ class Pakfire(object):
                logger.setup_logging(self.config)
                self.config.dump()
 
+               # Initialize the keyring.
+               self.keyring = keyring.Keyring(self)
+
                # Get more information about the distribution we are running
                # or building
                self.distro = distro.Distribution(self, distro_config)
@@ -181,9 +185,8 @@ class Pakfire(object):
 
                raise BuildError, arch
 
+       @staticmethod
        def check_is_ipfire(self):
-               return # XXX disabled for now
-
                ret = os.path.exists("/etc/ipfire-release")
 
                if not ret:
@@ -657,7 +660,7 @@ class Pakfire(object):
 
                return sorted(pkgs)
 
-       def repo_create(self, path, input_paths, type="binary"):
+       def repo_create(self, path, input_paths, key_id=None, type="binary"):
                assert type in ("binary", "source",)
 
                repo = repository.RepositoryDir(
@@ -671,6 +674,10 @@ class Pakfire(object):
                for input_path in input_paths:
                        repo.collect_packages(input_path)
 
+               # Sign the repository with the given key.
+               if key_id:
+                       repo.sign(key_id)
+
                repo.save()
 
                return repo
index 6d19e97fcbbcf4f1f431baaf744d26b3e27fd47e..f611c9f61c0e18cc8384888da04a8035b714d504 100644 (file)
@@ -20,6 +20,7 @@
 ###############################################################################
 
 import argparse
+import datetime
 import os
 import sys
 
@@ -481,6 +482,7 @@ class CliBuilder(Cli):
                sub_dist.add_argument("--resultdir", nargs="?",
                        help=_("Path were the output files should be copied to."))
 
+
        def parse_command_cache(self):
                # Implement the "cache" command.
                sub_cache = self.sub_commands.add_parser("cache",
@@ -660,8 +662,12 @@ class CliServer(Cli):
        def parse_command_repo_create(self, sub_commands):
                sub_create = sub_commands.add_parser("create",
                        help=_("Create a new repository index."))
-               sub_create.add_argument("path", nargs=1, help=_("Path to the packages."))
-               sub_create.add_argument("inputs", nargs="+", help=_("Path to input packages."))
+               sub_create.add_argument("path", nargs=1,
+                       help=_("Path to the packages."))
+               sub_create.add_argument("inputs", nargs="+",
+                       help=_("Path to input packages."))
+               sub_create.add_argument("--key", "-k", nargs="?",
+                       help=_("Key to sign the repository with."))
                sub_create.add_argument("action", action="store_const", const="repo_create")
 
        def parse_command_info(self):
@@ -705,7 +711,8 @@ class CliServer(Cli):
        def handle_repo_create(self):
                path = self.args.path[0]
 
-               pakfire.repo_create(path, self.args.inputs, **self.pakfire_args)
+               pakfire.repo_create(path, self.args.inputs, key_id=self.args.key,
+                       **self.pakfire_args)
 
        def handle_info(self):
                info = self.server.info()
@@ -937,3 +944,205 @@ class CliDaemon(Cli):
                # We cannot just kill the daemon, it needs a smooth shutdown.
                except (SystemExit, KeyboardInterrupt):
                        d.shutdown()
+
+
+class CliKey(Cli):
+       def __init__(self):
+               self.parser = argparse.ArgumentParser(
+                       description = _("Pakfire key command line interface."),
+               )
+
+               self.parse_common_arguments(repo_manage_switches=False,
+                       offline_switch=True)
+
+               # Add sub-commands.
+               self.sub_commands = self.parser.add_subparsers()
+
+               self.parse_command_init()
+               self.parse_command_generate()
+               self.parse_command_import()
+               self.parse_command_export()
+               self.parse_command_list()
+               self.parse_command_sign()
+               self.parse_command_verify()
+
+               # Finally parse all arguments from the command line and save them.
+               self.args = self.parser.parse_args()
+
+               # Create a pakfire instance.
+               self.pakfire = pakfire.Pakfire(**self.pakfire_args)
+
+               self.action2func = {
+                       "init"        : self.handle_init,
+                       "generate"    : self.handle_generate,
+                       "import"      : self.handle_import,
+                       "export"      : self.handle_export,
+                       "list"        : self.handle_list,
+                       "sign"        : self.handle_sign,
+                       "verify"      : self.handle_verify,
+               }
+
+       @property
+       def pakfire_args(self):
+               ret = {
+                       "mode" : "server",
+               }
+
+               return ret
+
+       def parse_command_init(self):
+               # Parse "init" command.
+               sub_init = self.sub_commands.add_parser("init",
+                       help=_("Initialize the local keyring."))
+               sub_init.add_argument("action", action="store_const", const="init")
+
+       def parse_command_generate(self):
+               # Parse "generate" command.
+               sub_gen = self.sub_commands.add_parser("generate",
+                       help=_("Import a key from file."))
+               sub_gen.add_argument("--realname", nargs=1,
+                       help=_("The real name of the owner of this key."))
+               sub_gen.add_argument("--email", nargs=1,
+                       help=_("The email address of the owner of this key."))
+               sub_gen.add_argument("action", action="store_const", const="generate")
+
+       def parse_command_import(self):
+               # Parse "import" command.
+               sub_import = self.sub_commands.add_parser("import",
+                       help=_("Import a key from file."))
+               sub_import.add_argument("filename", nargs=1,
+                       help=_("Filename of that key to import."))
+               sub_import.add_argument("action", action="store_const", const="import")
+
+       def parse_command_export(self):
+               # Parse "export" command.
+               sub_export = self.sub_commands.add_parser("export",
+                       help=_("Export a key to a file."))
+               sub_export.add_argument("keyid", nargs=1,
+                       help=_("The ID of the key to export."))
+               sub_export.add_argument("filename", nargs=1,
+                       help=_("Write the key to this file."))
+               sub_export.add_argument("action", action="store_const", const="export")
+
+       def parse_command_list(self):
+               # Parse "list" command.
+               sub_list = self.sub_commands.add_parser("list",
+                       help=_("List all imported keys."))
+               sub_list.add_argument("action", action="store_const", const="list")
+
+       def parse_command_sign(self):
+               # Implement the "sign" command.
+               sub_sign = self.sub_commands.add_parser("sign",
+                       help=_("Sign one or more packages."))
+               sub_sign.add_argument("--key", "-k", nargs=1,
+                       help=_("Key that is used sign the package(s)."))
+               sub_sign.add_argument("package", nargs="+",
+                       help=_("Package(s) to sign."))
+               sub_sign.add_argument("action", action="store_const", const="sign")
+
+       def parse_command_verify(self):
+               # Implement the "verify" command.
+               sub_verify = self.sub_commands.add_parser("verify",
+                       help=_("Verify one or more packages."))
+               #sub_verify.add_argument("--key", "-k", nargs=1,
+               #       help=_("Key that is used verify the package(s)."))
+               sub_verify.add_argument("package", nargs="+",
+                       help=_("Package(s) to verify."))
+               sub_verify.add_argument("action", action="store_const", const="verify")
+
+       def handle_init(self):
+               # Initialize the keyring...
+               pakfire.key_init(**self.pakfire_args)
+
+       def handle_generate(self):
+               realname = self.args.realname[0]
+               email    = self.args.email[0]
+
+               print _("Generating the key may take a moment...")
+               print
+
+               # Generate the key.
+               fpr = pakfire.key_generate(realname, email, **self.pakfire_args)
+
+               # Dump all information about the new key.
+               for line in self.dump_key(fpr):
+                       print line
+
+       def handle_import(self):
+               filename = self.args.filename[0]
+
+               # Simply import the file.
+               pakfire.key_import(filename, **self.pakfire_args)
+
+       def handle_export(self):
+               keyid    = self.args.keyid[0]
+               filename = self.args.filename[0]
+
+               pakfire.key_export(keyid, filename, **self.pakfire_args)
+
+       def handle_list(self):
+               lines = pakfire.key_list(**self.pakfire_args)
+
+               for line in lines:
+                       print line
+
+       def handle_sign(self):
+               # Get the files from the command line options
+               files = []
+
+               for file in self.args.package:
+                       # Check, if we got a regular file
+                       if os.path.exists(file):
+                               file = os.path.abspath(file)
+                               files.append(file)
+
+                       else:
+                               raise FileNotFoundError, file
+
+               key = self.args.key[0]
+
+               for file in files:
+                       # Open the package.
+                       pkg = packages.open(self.pakfire, None, file)
+
+                       print _("Signing %s...") % pkg.friendly_name
+                       pkg.sign(key)
+
+       def handle_verify(self):
+               # Get the files from the command line options
+               files = []
+
+               for file in self.args.package:
+                       # Check, if we got a regular file
+                       if os.path.exists(file) and not os.path.isdir(file):
+                               file = os.path.abspath(file)
+                               files.append(file)
+
+               for file in files:
+                       # Open the package.
+                       pkg = packages.open(self.pakfire, None, file)
+
+                       print _("Verifying %s...") % pkg.friendly_name
+                       sigs = pkg.verify()
+
+                       for sig in sigs:
+                               key = self.pakfire.keyring.get_key(sig.fpr)
+                               if key:
+                                       subkey = key.subkeys[0]
+
+                                       print "  %s %s" % (subkey.fpr[-16:], key.uids[0].uid)
+                                       if sig.validity:
+                                               print "    %s" % _("This signature is valid.")
+
+                               else:
+                                       print "  %s <%s>" % (sig.fpr, _("Unknown key"))
+                                       print "    %s" % _("Could not check if this signature is valid.")
+
+                               created = datetime.datetime.fromtimestamp(sig.timestamp)
+                               print "    %s" % _("Created: %s") % created
+
+                               if sig.exp_timestamp:
+                                       expires = datetime.datetime.fromtimestamp(sig.exp_timestamp)
+                                       print "    %s" % _("Expires: %s") % expires
+
+                       print # Empty line
index 082eb27e49acac307ee90401a0dac97fdbfd0d9d..4c380fefc388f96273b65e2f654134bb1e9fe1c1 100644 (file)
@@ -34,6 +34,8 @@ CONFIG_DIR = os.path.join(SYSCONFDIR, "pakfire.repos.d")
 CONFIG_DIR_EXT = ".repo"
 CONFIG_FILE = os.path.join(SYSCONFDIR, "pakfire.conf")
 
+KEYRING_DIR = os.path.join(SYSCONFDIR, "pakfire.d", "gnupg")
+
 CACHE_DIR = "/var/cache/pakfire"
 CCACHE_CACHE_DIR = os.path.join(CACHE_DIR, "ccache")
 CACHE_ENVIRON_DIR = os.path.join(CACHE_DIR, "environments")
diff --git a/python/pakfire/keyring.py b/python/pakfire/keyring.py
new file mode 100644 (file)
index 0000000..492591d
--- /dev/null
@@ -0,0 +1,195 @@
+#!/usr/bin/python
+###############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2012 Pakfire development team                                 #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+import datetime
+import gpgme
+import io
+import os
+
+import logging
+log = logging.getLogger("pakfire")
+
+from constants import *
+from i18n import _
+from system import system
+
+class Keyring(object):
+       def __init__(self, pakfire):
+               self.pakfire = pakfire
+               
+               # Configure the environment.
+               os.environ["GNUPGHOME"] = self.path
+               self.create_path()
+
+       def __del__(self):
+               del os.environ["GNUPGHOME"]
+
+       @property
+       def path(self):
+               return KEYRING_DIR
+
+       def create_path(self):
+               filename = os.path.join(self.path, "gnupg.conf")
+
+               if os.path.exists(filename):
+                       return
+
+               if not os.path.exists(self.path):
+                       os.makedirs(self.path)
+                       # XXX chmod 700
+
+               # Create a default gnupg.conf.
+               f = open(filename, "w")
+               f.write("# This is a default gnupg configuration file create by\n")
+               f.write("# Pakfire %s.\n" % PAKFIRE_VERSION)
+               f.close()
+               # XXX chmod 600
+
+       def init(self):
+               log.info(_("Initializing local keyring..."))
+
+               hostname, domainname = system.hostname.split(".", 1)
+
+               self.gen_key(system.hostname, "%s@%s" % (hostname, domainname))
+
+       def dump_key(self, keyfp):
+               ret = []
+
+               ctx = gpgme.Context()
+               key = ctx.get_key(keyfp)
+
+               for uid in key.uids:
+                       ret.append(uid.uid)
+
+               ret.append("  " + _("Fingerprint: %s") % keyfp)
+               ret.append("")
+
+               for subkey in key.subkeys:
+                       ret.append("  " + _("Subkey: %s") % subkey.keyid)
+                       if subkey.expired:
+                               ret.append("    %s" % _("This key has expired!"))
+
+                       if subkey.secret:
+                               ret.append("    %s" % _("This is a secret key."))
+
+                       created = datetime.datetime.fromtimestamp(subkey.timestamp)
+                       ret.append("    %s" % _("Created: %s") % created)
+                       if subkey.expires:
+                               expires = datetime.datetime.fromtimestamp(subkey.expires)
+                               ret.append("    %s" % _("Expires: %s") % expires)
+                       else:
+                               ret.append("    %s" % _("This key does not expire."))
+
+                       if subkey.pubkey_algo == gpgme.PK_RSA:
+                               ret.append("    RSA/%s" % subkey.length)
+
+                       ret.append("")
+
+               return ret
+
+       def get_key(self, keyid):
+               ctx = gpgme.Context()
+
+               try:
+                       return ctx.get_key(keyid)
+               except gpgme.GpgmeError:
+                       return None
+
+       def gen_key(self, realname, email):
+               params = """
+                       <GnupgKeyParms format="internal">
+                               Key-Type: RSA
+                               Key-Usage: sign
+                               Key-Length: 2048
+                               Name-Real: %s
+                               Name-Email: %s
+                               Expire-Date: 0
+                       </GnupgKeyParms>
+               """ % (realname, email)
+
+               # Create a new context.
+               ctx = gpgme.Context()
+
+               # Generate the key.
+               result = ctx.genkey(params)
+
+               # Return the fingerprint of the generated key.
+               return result.fpr
+
+       def import_key(self, keyfile):
+               ret = []
+
+               ctx = gpgme.Context()
+
+               f = open(keyfile, "rb")
+               res = ctx.import_(f)
+               f.close()
+
+               log.info(_("Successfully import key %s.") % keyfile)
+
+       def export_key(self, keyid, keyfile):
+               ctx = gpgme.Context()
+               ctx.armor = True
+
+               keydata = io.BytesIO()
+               ctx.export(keyid, keydata)
+
+               f = open(keyfile, "wb")
+               f.write(keydata.getvalue())
+               f.close()
+
+       def list_keys(self):
+               ret = []
+
+               ctx = gpgme.Context()
+
+               keys = [k.subkeys[0].keyid for k in ctx.keylist(None, True)]
+
+               for key in keys:
+                       ret += self.dump_key(key)
+
+               return ret
+
+       def sign(self, keyid, cleartext):
+               ctx = gpgme.Context()
+               ctx.armor = True
+
+               key = ctx.get_key(keyid)
+               ctx.signers = [key,]
+
+               cleartext = io.BytesIO(cleartext)
+               signature = io.BytesIO()
+
+               ctx.sign(cleartext, signature, gpgme.SIG_MODE_DETACH)
+
+               return signature.getvalue()
+
+       def verify(self, signature, cleartext):
+               # Create context.
+               ctx = gpgme.Context()
+
+               signature = io.BytesIO(signature)
+               cleartext = io.BytesIO(cleartext)
+
+               # Verify the data.
+               sigs = ctx.verify(signature, cleartext, None)
+
+               return sigs
index dc5fdaded98e702c37a7369ee4af9e5b41a40f34..c1c8cb022ed44e27ca82a9265ec95bc33c8203f8 100644 (file)
@@ -21,7 +21,7 @@
 
 import tarfile
 
-from file import BinaryPackage, InnerTarFile, SourcePackage
+from file import BinaryPackage, FilePackage, InnerTarFile, SourcePackage
 from installed import DatabasePackage, InstalledPackage
 from solv import SolvPackage
 
index e1f7238eddaa85a8c003c2220b08209952057882..12e14423604c8ce86e108143fcac5eae7c7341f1 100644 (file)
@@ -194,8 +194,8 @@ class FilePackage(Package):
                # A file package is always local.
                return True
 
-       def open_archive(self):
-               return tarfile.open(self.filename, format=tarfile.PAX_FORMAT)
+       def open_archive(self, mode="r"):
+               return tarfile.open(self.filename, mode=mode, format=tarfile.PAX_FORMAT)
 
        def extract(self, message=None, prefix=None):
                log.debug("Extracting package %s" % self.friendly_name)
@@ -521,28 +521,187 @@ class FilePackage(Package):
 
                return self.__payload_compression or "none"
 
+       ### SIGNATURE STUFF
+
        @property
-       def signature(self):
-               # XXX needs to be replaced
+       def signatures(self):
                """
-                       Read the signature from the archive or return None if no
-                       signature does exist.
+                       Read the signatures from the archive.
                """
-               ret = None
-               try:
-                       a = self.open_archive()
-                       f = a.extractfile("signature")
+               ret = {}
+
+               # Open the archive for reading.
+               a = self.open_archive()
+
+               for member in a.getmembers():
+                       # Skip all files that are not a signature.
+                       if not member.name.startswith("signatures/"):
+                               continue
+
+                       # Get the ID of the key.
+                       key_id = os.path.basename(member.name)
+
+                       # Get the content of the signature file.
+                       f = a.extractfile(member.name)
+                       ret[key_id] = f.read()
+                       f.close()
+
+               # Close the archive.
+               a.close()
+
+               return ret
+
+       def has_signature(self, key_id):
+               """
+                       Check if the file a signature of the given key.
+               """
+               return self.signatures.has_key(key_id)
+
+       def __has_hardlinks(self):
+               """
+                       Returns True when a file has a hardlink.
+               """
+               res = os.stat(self.filename)
+
+               return res.st_nlink > 1
+
+       def __remove_hardlinks(self):
+               """
+                       Remove all hardlinks from this file that we can alter it in place.
+               """
+               if not self.__has_hardlinks():
+                       return
+
+               # Open a file descriptor to the old file and remove the link from
+               # the filesystem.
+               f = open(self.filename, "rb")
+               os.unlink(self.filename)
+
+               # Create a new file with the exact same name for copying the data
+               # to.
+               g = open(self.filename, "wb")
+
+               # Copy the data.
+               while True:
+                       buf = f.read(BUFFER_SIZE)
+                       if not buf:
+                               break
+
+                       g.write(buf)
+
+               # Close all files.
+               f.close()
+               g.close()
+
+               # Make sure the whole process above worked fine.
+               assert self.__has_hardlinks() is False
+
+       def sign(self, key_id):
+               """
+                       Sign the package with the given key.
+               """
+               # First check if the package has already been signed with this key.
+               # If true, we do not have anything to do here.
+               if self.has_signature(key_id):
+                       return
+
+               # Remove all hardlinks.
+               self.__remove_hardlinks()
+
+               # XXX verify the content of the file here.
+
+               # Open the archive and read the checksum file.
+               a = self.open_archive()
+
+               f = a.extractfile("chksums")
+               cleartext = f.read()
+
+               f.close()
+               a.close()
+
+               # Create the signature.
+               signature = self.pakfire.keyring.sign(key_id, cleartext)
 
-                       ret = f.read()
+               # Write the signature to a temporary file.
+               trash, signature_file = tempfile.mkstemp()
 
+               try:
+                       f = open(signature_file, mode="w")
+                       f.write(signature)
                        f.close()
+
+                       # Reopen the outer tarfile in write mode and append
+                       # the new signature.
+                       a = self.open_archive("a")
+                       a.add(signature_file, "signatures/%s" % key_id)
                        a.close()
 
-               except KeyError:
-                       # signature file could not be found
-                       pass
+               finally:
+                       if os.path.exists(signature_file):
+                               os.unlink(signature_file)
+
+       def verify(self):
+               """
+                       Verify the tarball against the given key.
+
+                       If not key is given, only the checksums are compared to
+                       the actual data.
+               """
+
+               # XXX replace Exception
+
+               # Read the data of the checksum file.
+               a = self.open_archive()
+               f = a.extractfile("chksums")
+               chksums = f.read()
+               f.close()
+               a.close()
+
+               sigs = []
+               for signature in self.signatures.values():
+                       sigs += self.pakfire.keyring.verify(signature, chksums)
+
+               # Open the archive to access all files we will need.
+               a = self.open_archive()
+
+               # Read the chksums file.
+               chksums = {}
+               f = a.extractfile("chksums")
+               for line in f.readlines():
+                       filename, chksum = line.split()
+                       chksums[filename] = chksum
+               f.close()
+               a.close()
+
+               for filename, chksum in chksums.items():
+                       ret = self.check_chksum(filename, chksum)
+
+                       if ret:
+                               log.debug("Checksum of %s matches." % filename)
+                               continue
+                       else:
+                               log.debug("Checksum of %s does not match." % filename)
+
+                       raise Exception, "Checksum does not match: %s" % filename
+
+               return sigs
+
+       def check_chksum(self, filename, chksum, algo="sha512"):
+               a = self.open_archive()
+               f = a.extractfile(filename)
+
+               h = hashlib.new(algo)
+               while True:
+                       buf = f.read(BUFFER_SIZE)
+                       if not buf:
+                               break
+
+                       h.update(buf)
+
+               f.close()
+               a.close()
 
-               return ret or None
+               return h.hexdigest() == chksum
 
        @property
        def hash1(self):
index c319814dad6ea86d4043a9204d78d917a24aec6e..9dda6bb96180447e1b2781496e04147ea1352a06 100644 (file)
@@ -52,9 +52,6 @@ class Index(object):
        def __repr__(self):
                return "<%s %s>" % (self.__class__.__name__, self.repo)
 
-       def __len(self):
-               return len(self.repo)
-
        @property
        def cache(self):
                return self.repo.cache
index 800019e52217287521f824428c2884097c4d4536..a2936e32e3606e37a2307fbf2c35c8333e0f7bd1 100644 (file)
@@ -75,38 +75,53 @@ class RepositoryDir(base.RepositoryFactory):
                        # The path of the package in the repository
                        repo_filename = os.path.join(self.path, os.path.basename(pkg.filename))
 
-                       # Do we need to copy the package files?
-                       copy = True
-
                        # Check, if the package does already exists and check if the
                        # files are really equal.
                        if os.path.exists(repo_filename):
                                pkg_exists = packages.open(self.pakfire, self, repo_filename)
-                               copy = False
-
-                               # Check UUID at first (faster) and check the file hash to be
-                               # absolutely sure.
-                               # Otherwise, unlink the existing file and replace it with the
-                               # new one.
-                               if pkg.uuid != pkg_exists.uuid and pkg.hash1 != pkg_exists.hash1:
-                                       # Do not copy the file if it is already okay.
-                                       copy = True
-                                       os.unlink(repo_filename)
-
-                               del pkg_exists
-
-                       if copy:
-                               log.debug("Copying package '%s' to repository." % pkg)
-                               repo_dirname = os.path.dirname(repo_filename)
-                               if not os.path.exists(repo_dirname):
-                                       os.makedirs(repo_dirname)
-
-                               # Try to use a hard link if possible, if we cannot do that we simply
-                               # copy the file.
-                               try:
-                                       os.link(pkg.filename, repo_filename)
-                               except OSError:
-                                       shutil.copy2(pkg.filename, repo_filename)
+
+                               # Check UUID to see if the file needs to be copied.
+                               if pkg.uuid == pkg_exists.uuid:
+                                       continue
+
+                       log.debug("Copying package '%s' to repository." % pkg)
+                       repo_dirname = os.path.dirname(repo_filename)
+                       if not os.path.exists(repo_dirname):
+                               os.makedirs(repo_dirname)
+
+                       # Try to use a hard link if possible, if we cannot do that we simply
+                       # copy the file.
+                       try:
+                               os.link(pkg.filename, repo_filename)
+                       except OSError:
+                               shutil.copy2(pkg.filename, repo_filename)
+
+       def sign(self, key_id):
+               """
+                       Sign all packages with the given key.
+               """
+               # Create progressbar.
+               pb = util.make_progress(_("Signing packages..."), len(self), eta=True)
+               i = 0
+
+               # Create a new index (because package checksums will change).
+               for pkg in self:
+                       if pb:
+                               i += 1
+                               pb.update(i)
+
+                       # Create the full path to the file.
+                       filename = os.path.join(self.path, pkg.filename)
+                       pkg = packages.open(self.pakfire, self, filename)
+
+                       # Sign the package.
+                       pkg.sign(key_id)
+
+               if pb:
+                       pb.finish()
+
+               # Recreate the index because file checksums may have changed.
+               self.index.update(force=True)
 
        def save(self, path=None, algo="xz"):
                """
@@ -123,7 +138,6 @@ class RepositoryDir(base.RepositoryFactory):
 
                # Remove all pre-existing metadata.
                if os.path.exists(metapath):
-                       print "Removing", metapath
                        util.rm(metapath)
 
                # Create directory for metdadata.
index eb1315acb0f62df2cfd4d2521c45d3dc18b03fef..4448b69f5ca7f406dfb07e5b0d586d51111ced1e 100644 (file)
@@ -53,6 +53,7 @@ install: $(SCRIPTS)
        ln -svf ../..$(SCRIPT_DIR)/pakfire-multicall.py $(DESTDIR)/usr/bin/pakfire-builder
        ln -svf ../..$(SCRIPT_DIR)/pakfire-multicall.py $(DESTDIR)/usr/bin/pakfire-client
        ln -svf ../..$(SCRIPT_DIR)/pakfire-multicall.py $(DESTDIR)/usr/bin/pakfire-daemon
+       ln -svf ../..$(SCRIPT_DIR)/pakfire-multicall.py $(DESTDIR)/usr/bin/pakfire-key
        ln -svf ../..$(SCRIPT_DIR)/pakfire-multicall.py $(DESTDIR)/usr/bin/pakfire-server
        ln -svf pakfire-multicall.py                    $(DESTDIR)$(SCRIPT_DIR)/builder
 
index 0e5ab8073937b96d7f4eea27f40a0d3e68651427..b7547c198c75f1143ac87eb577a27af352ef8fba 100755 (executable)
@@ -38,6 +38,7 @@ basename2cls = {
        "pakfire-builder" : CliBuilder,
        "pakfire-client"  : CliClient,
        "pakfire-daemon"  : CliDaemon,
+       "pakfire-key"     : CliKey,
        "pakfire-server"  : CliServer,
        "builder"         : CliBuilderIntern,
 }