[monotone] Add patches for building with Botan 1.10, Lua 5.2, and Texinfo >= 5.0.
Thomas Moschny
thm at fedoraproject.org
Tue Oct 8 19:48:49 UTC 2013
commit 5235e919579bd021c86bc7dd1f6b208e7033db7c
Author: Thomas Moschny <thm at fedoraproject.org>
Date: Tue Oct 8 21:44:31 2013 +0200
Add patches for building with Botan 1.10, Lua 5.2, and Texinfo >= 5.0.
monotone-1.0-botan-1.10.patch | 944 ++++++++++++++++++++++++++++++++++++++++
monotone-1.0-fix-texinfo.patch | 623 ++++++++++++++++++++++++++
monotone-1.0-lua-5.2.patch | 752 ++++++++++++++++++++++++++++++++
monotone.spec | 18 +-
4 files changed, 2336 insertions(+), 1 deletions(-)
---
diff --git a/monotone-1.0-botan-1.10.patch b/monotone-1.0-botan-1.10.patch
new file mode 100644
index 0000000..0da8f2f
--- /dev/null
+++ b/monotone-1.0-botan-1.10.patch
@@ -0,0 +1,944 @@
+From: Thomas Moschny <thomas.moschny at gmx.de>
+Subject: [PATCH] t/botan-1.10
+
+Botan 1.10 support.
+
+Apply patches from these upstream commits:
+
+f4feb3fdc68e4f955909450b2dcb3ff9312dbc9e
+9ff6e41adc6f40ae054fb4487f356bf69324dbdb
+8861f8555ef90a04a99404e9f8d5510b2ddb10e6
+
+---
+ src/database.cc | 42 ++++++++++++------
+ src/gzip.cc | 48 +++++++++++++-------
+ src/gzip.hh | 17 ++++++-
+ src/key_packet.cc | 4 +-
+ src/key_store.cc | 129 +++++++++++++++++++++++++++++++++++++++++++++---------
+ src/monotone.cc | 56 +++++++++++++++++-------
+ src/packet.cc | 22 ++++++++--
+ src/packet.hh | 19 ++++++++
+ src/sha1.cc | 5 ++-
+ src/ssh_agent.cc | 6 +--
+ src/transforms.cc | 15 ++++---
+ 11 files changed, 279 insertions(+), 84 deletions(-)
+
+diff --git a/src/database.cc b/src/database.cc
+index 520fddd..c18517c 100644
+--- a/src/database.cc
++++ b/src/database.cc
+@@ -98,12 +98,15 @@ using boost::get;
+ using boost::tuple;
+ using boost::lexical_cast;
+
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,5)
++using Botan::PK_Encryptor_EME;
++#else
+ using Botan::PK_Encryptor;
++#endif
+ using Botan::PK_Verifier;
+ using Botan::SecureVector;
+ using Botan::X509_PublicKey;
+ using Botan::RSA_PublicKey;
+-using Botan::get_pk_encryptor;
+
+ int const one_row = 1;
+ int const one_col = 1;
+@@ -3425,9 +3428,8 @@ database::encrypt_rsa(key_id const & pub_id,
+ rsa_pub_key pub;
+ get_key(pub_id, pub);
+
+- SecureVector<Botan::byte> pub_block;
+- pub_block.set(reinterpret_cast<Botan::byte const *>(pub().data()),
+- pub().size());
++ SecureVector<Botan::byte> pub_block
++ (reinterpret_cast<Botan::byte const *>(pub().data()), pub().size());
+
+ shared_ptr<X509_PublicKey> x509_key(Botan::X509::load_key(pub_block));
+ shared_ptr<RSA_PublicKey> pub_key
+@@ -3436,23 +3438,32 @@ database::encrypt_rsa(key_id const & pub_id,
+ throw recoverable_failure(origin::system,
+ "Failed to get RSA encrypting key");
+
++ SecureVector<Botan::byte> ct;
++
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,5)
++ PK_Encryptor_EME encryptor(*pub_key, "EME1(SHA-1)");
++ ct = encryptor.encrypt(
++ reinterpret_cast<Botan::byte const *>(plaintext.data()),
++ plaintext.size(), lazy_rng::get());
++#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
+ shared_ptr<PK_Encryptor>
+ encryptor(get_pk_encryptor(*pub_key, "EME1(SHA-1)"));
+
+- SecureVector<Botan::byte> ct;
+-
+-#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
+ ct = encryptor->encrypt(
+ reinterpret_cast<Botan::byte const *>(plaintext.data()),
+ plaintext.size(), lazy_rng::get());
+ #else
++ shared_ptr<PK_Encryptor>
++ encryptor(Botan::get_pk_encryptor(*pub_key, "EME1(SHA-1)"));
++
+ ct = encryptor->encrypt(
+ reinterpret_cast<Botan::byte const *>(plaintext.data()),
+ plaintext.size());
+ #endif
+- ciphertext = rsa_oaep_sha_data(string(reinterpret_cast<char const *>(ct.begin()),
+- ct.size()),
+- origin::database);
++
++ ciphertext = rsa_oaep_sha_data(
++ string(reinterpret_cast<char const *>(ct.begin()), ct.size()),
++ origin::database);
+ }
+
+ cert_status
+@@ -3471,14 +3482,13 @@ database::check_signature(key_id const & id,
+ else
+ {
+ rsa_pub_key pub;
+- SecureVector<Botan::byte> pub_block;
+
+ if (!public_key_exists(id))
+ return cert_unknown;
+
+ get_key(id, pub);
+- pub_block.set(reinterpret_cast<Botan::byte const *>(pub().data()),
+- pub().size());
++ SecureVector<Botan::byte> pub_block
++ (reinterpret_cast<Botan::byte const *>(pub().data()), pub().size());
+
+ L(FL("building verifier for %d-byte pub key") % pub_block.size());
+ shared_ptr<X509_PublicKey> x509_key(Botan::X509::load_key(pub_block));
+@@ -3488,7 +3498,11 @@ database::check_signature(key_id const & id,
+ E(pub_key, id.inner().made_from,
+ F("Failed to get RSA verifying key for %s") % id);
+
+- verifier.reset(get_pk_verifier(*pub_key, "EMSA3(SHA-1)"));
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,10,0)
++ verifier.reset(new Botan::PK_Verifier(*pub_key, "EMSA3(SHA1)"));
++#else
++ verifier.reset(Botan::get_pk_verifier(*pub_key, "EMSA3(SHA-1)"));
++#endif
+
+ /* XXX This is ugly. We need to keep the key around
+ * as long as the verifier is around, but the shared_ptr will go
+diff --git a/src/gzip.cc b/src/gzip.cc
+index b74af6d..2cfea09 100644
+--- a/src/gzip.cc
++++ b/src/gzip.cc
+@@ -110,7 +110,7 @@ Gzip_Compression::Gzip_Compression(u32bit l) :
+ if(deflateInit2(&(zlib->stream), level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK)
+ {
+ delete zlib; zlib = 0;
+- throw Exception("Gzip_Compression: Memory allocation error");
++ throw Memory_Exhaustion();
+ }
+ }
+
+@@ -137,7 +137,7 @@ void Gzip_Compression::start_msg()
+ /*************************************************
+ * Compress Input with Gzip *
+ *************************************************/
+-void Gzip_Compression::write(const byte input[], u32bit length)
++void Gzip_Compression::write(const byte input[], filter_length_t length)
+ {
+
+ count += length;
+@@ -152,7 +152,7 @@ void Gzip_Compression::write(const byte input[], u32bit length)
+ zlib->stream.avail_out = buffer.size();
+ int rc = deflate(&(zlib->stream), Z_NO_FLUSH);
+ if (rc != Z_OK && rc != Z_STREAM_END)
+- throw Exception("Internal error in Gzip_Compression deflate.");
++ throw Invalid_State("Internal error in Gzip_Compression deflate.");
+ send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
+ }
+ }
+@@ -172,7 +172,7 @@ void Gzip_Compression::end_msg()
+ zlib->stream.avail_out = buffer.size();
+ rc = deflate(&(zlib->stream), Z_FINISH);
+ if (rc != Z_OK && rc != Z_STREAM_END)
+- throw Exception("Internal error in Gzip_Compression finishing deflate.");
++ throw Invalid_State("Internal error in Gzip_Compression finishing deflate.");
+ send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
+ }
+
+@@ -228,7 +228,7 @@ Gzip_Decompression::Gzip_Decompression() : buffer(DEFAULT_BUFFERSIZE),
+ no_writes(true), pipe(new Hash_Filter("CRC32")), footer(0)
+ {
+ if (DEFAULT_BUFFERSIZE < sizeof(GZIP::GZIP_HEADER))
+- throw Exception("DEFAULT_BUFFERSIZE is too small");
++ throw Decoding_Error("DEFAULT_BUFFERSIZE is too small");
+
+ zlib = new Zlib_Stream;
+
+@@ -237,7 +237,7 @@ Gzip_Decompression::Gzip_Decompression() : buffer(DEFAULT_BUFFERSIZE),
+ if(inflateInit2(&(zlib->stream), -15) != Z_OK)
+ {
+ delete zlib; zlib = 0;
+- throw Exception("Gzip_Decompression: Memory allocation error");
++ throw Memory_Exhaustion();
+ }
+ }
+
+@@ -256,7 +256,7 @@ Gzip_Decompression::~Gzip_Decompression()
+ void Gzip_Decompression::start_msg()
+ {
+ if (!no_writes)
+- throw Exception("Gzip_Decompression: start_msg after already writing");
++ throw Decoding_Error("Gzip_Decompression: start_msg after already writing");
+
+ pipe.start_msg();
+ datacount = 0;
+@@ -267,7 +267,7 @@ void Gzip_Decompression::start_msg()
+ /*************************************************
+ * Decompress Input with Gzip *
+ *************************************************/
+-void Gzip_Decompression::write(const byte input[], u32bit length)
++void Gzip_Decompression::write(const byte input[], filter_length_t length)
+ {
+ if(length) no_writes = false;
+
+@@ -277,15 +277,16 @@ void Gzip_Decompression::write(const byte input[], u32bit length)
+ u32bit eat_len = eat_footer(input, length);
+ input += eat_len;
+ length -= eat_len;
+- if (length == 0)
+- return;
+ }
+
++ if (length == 0)
++ return;
++
+ // Check the gzip header
+ if (pos < sizeof(GZIP::GZIP_HEADER))
+ {
+- u32bit len = std::min((u32bit)sizeof(GZIP::GZIP_HEADER)-pos, length);
+- u32bit cmplen = len;
++ filter_length_t len = std::min((filter_length_t)sizeof(GZIP::GZIP_HEADER)-pos, length);
++ filter_length_t cmplen = len;
+ // The last byte is the OS flag - we don't care about that
+ if (pos + len - 1 >= GZIP::HEADER_POS_OS)
+ cmplen--;
+@@ -317,8 +318,8 @@ void Gzip_Decompression::write(const byte input[], u32bit length)
+ if(rc == Z_NEED_DICT)
+ throw Decoding_Error("Gzip_Decompression: Need preset dictionary");
+ if(rc == Z_MEM_ERROR)
+- throw Exception("Gzip_Decompression: Memory allocation error");
+- throw Exception("Gzip_Decompression: Unknown decompress error");
++ throw Memory_Exhaustion();
++ throw Decoding_Error("Gzip_Decompression: Unknown decompress error");
+ }
+ send(buffer.begin(), buffer.size() - zlib->stream.avail_out);
+ pipe.write(buffer.begin(), buffer.size() - zlib->stream.avail_out);
+@@ -346,8 +347,14 @@ u32bit Gzip_Decompression::eat_footer(const byte input[], u32bit length)
+ if (footer.size() >= GZIP::FOOTER_LENGTH)
+ throw Decoding_Error("Gzip_Decompression: Data integrity error in footer");
+
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++ size_t eat_len = std::min(GZIP::FOOTER_LENGTH-footer.size(),
++ static_cast<size_t>(length));
++ footer += std::make_pair(input, eat_len);
++#else
+ u32bit eat_len = std::min(GZIP::FOOTER_LENGTH-footer.size(), length);
+ footer.append(input, eat_len);
++#endif
+
+ if (footer.size() == GZIP::FOOTER_LENGTH)
+ {
+@@ -364,7 +371,7 @@ u32bit Gzip_Decompression::eat_footer(const byte input[], u32bit length)
+ void Gzip_Decompression::check_footer()
+ {
+ if (footer.size() != GZIP::FOOTER_LENGTH)
+- throw Exception("Gzip_Decompression: Error finalizing decompression");
++ throw Decoding_Error("Gzip_Decompression: Error finalizing decompression");
+
+ pipe.end_msg();
+
+@@ -377,7 +384,12 @@ void Gzip_Decompression::check_footer()
+ for (int i = 0; i < 4; i++)
+ buf[3-i] = tmpbuf[i];
+
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++ tmpbuf.resize(4);
++ tmpbuf.copy(footer.begin(), 4);
++#else
+ tmpbuf.set(footer.begin(), 4);
++#endif
+ if (buf != tmpbuf)
+ throw Decoding_Error("Gzip_Decompression: Data integrity error - CRC32 error");
+
+@@ -400,7 +412,7 @@ void Gzip_Decompression::end_msg()
+ // read, clear() will reset no_writes
+ if(no_writes) return;
+
+- throw Exception("Gzip_Decompression: didn't find footer");
++ throw Decoding_Error("Gzip_Decompression: didn't find footer");
+
+ }
+
+@@ -412,7 +424,11 @@ void Gzip_Decompression::clear()
+ no_writes = true;
+ inflateReset(&(zlib->stream));
+
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++ footer.clear();
++#else
+ footer.destroy();
++#endif
+ pos = 0;
+ datacount = 0;
+ }
+diff --git a/src/gzip.hh b/src/gzip.hh
+index f3ea628..5c25fc9 100644
+--- a/src/gzip.hh
++++ b/src/gzip.hh
+@@ -7,11 +7,18 @@
+ #ifndef BOTAN_EXT_GZIP_H__
+ #define BOTAN_EXT_GZIP_H__
+
++#include <botan/version.h>
+ #include <botan/filter.h>
+ #include <botan/pipe.h>
+
+ namespace Botan {
+
++#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,9,4)
++// Only 1.9.4 and newer export the Memory_Exception. Give this gzip
++// implementation something compatible to work with.
++typedef std::bad_alloc Memory_Exhaustion;
++#endif
++
+ namespace GZIP {
+
+ /* A basic header - we only need to set the IDs and compression method */
+@@ -30,13 +37,19 @@ namespace GZIP {
+
+ }
+
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++typedef size_t filter_length_t;
++#else
++typedef u32bit filter_length_t;
++#endif
++
+ /*************************************************
+ * Gzip Compression Filter *
+ *************************************************/
+ class Gzip_Compression : public Filter
+ {
+ public:
+- void write(const byte input[], u32bit length);
++ void write(const byte input[], filter_length_t length);
+ void start_msg();
+ void end_msg();
+ std::string name() const { return "Gzip_Compression"; }
+@@ -60,7 +73,7 @@ class Gzip_Compression : public Filter
+ class Gzip_Decompression : public Filter
+ {
+ public:
+- void write(const byte input[], u32bit length);
++ void write(const byte input[], filter_length_t length);
+ void start_msg();
+ void end_msg();
+ std::string name() const { return "Gzip_Decompression"; }
+diff --git a/src/key_packet.cc b/src/key_packet.cc
+index ccd0e06..3a56c69 100644
+--- a/src/key_packet.cc
++++ b/src/key_packet.cc
+@@ -106,8 +106,8 @@ namespace
+ void validate_public_key_data(string const & name, string const & keydata) const
+ {
+ string decoded = decode_base64_as<string>(keydata, origin::user);
+- Botan::SecureVector<Botan::byte> key_block;
+- key_block.set(reinterpret_cast<Botan::byte const *>(decoded.c_str()), decoded.size());
++ Botan::SecureVector<Botan::byte> key_block
++ (reinterpret_cast<Botan::byte const *>(decoded.c_str()), decoded.size());
+ try
+ {
+ Botan::X509::load_key(key_block);
+diff --git a/src/key_store.cc b/src/key_store.cc
+index ac8b8bb..a0c6494 100644
+--- a/src/key_store.cc
++++ b/src/key_store.cc
+@@ -55,6 +55,7 @@ using Botan::PK_Signer;
+ using Botan::Pipe;
+ using Botan::get_pk_decryptor;
+ using Botan::get_cipher;
++using Botan::byte;
+
+
+ typedef pair<key_name, keypair> key_info;
+@@ -572,13 +573,21 @@ key_store_state::decrypt_private_key(key_id const & id,
+ try // with empty passphrase
+ {
+ Botan::DataSource_Memory ds(kp.priv());
+-#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++ pkcs8_key.reset(Botan::PKCS8::load_key(ds, lazy_rng::get(), Dummy_UI()));
++#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
+ pkcs8_key.reset(Botan::PKCS8::load_key(ds, lazy_rng::get(), ""));
+ #else
+ pkcs8_key.reset(Botan::PKCS8::load_key(ds, ""));
+ #endif
+ }
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++ catch (Passphrase_Required & e)
++#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,4)
++ catch (Botan::Invalid_Argument & e)
++#else
+ catch (Botan::Exception & e)
++#endif
+ {
+ L(FL("failed to load key with no passphrase: %s") % e.what());
+
+@@ -605,13 +614,18 @@ key_store_state::decrypt_private_key(key_id const & id,
+ {
+ Botan::DataSource_Memory ds(kp.priv());
+ #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
+- pkcs8_key.reset(Botan::PKCS8::load_key(ds, lazy_rng::get(), phrase()));
++ pkcs8_key.reset(Botan::PKCS8::load_key(ds, lazy_rng::get(),
++ phrase()));
+ #else
+ pkcs8_key.reset(Botan::PKCS8::load_key(ds, phrase()));
+ #endif
+ break;
+ }
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,4)
++ catch (Botan::Invalid_Argument)
++#else
+ catch (Botan::Exception & e)
++#endif
+ {
+ cycles++;
+ L(FL("decrypt_private_key: failure %d to load encrypted key: %s")
+@@ -697,9 +711,18 @@ key_store::create_key_pair(database & db,
+
+ // serialize and maybe encrypt the private key
+ keypair kp;
+- SecureVector<Botan::byte> pubkey, privkey;
++ SecureVector<byte> pubkey, privkey;
+
+ unfiltered_pipe->start_msg();
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,10,0)
++ if ((*maybe_passphrase)().length())
++ unfiltered_pipe->write(
++ Botan::PKCS8::BER_encode(priv, lazy_rng::get(),
++ (*maybe_passphrase)(),
++ "PBE-PKCS5v20(SHA-1,TripleDES/CBC)"));
++ else
++ unfiltered_pipe->write(Botan::PKCS8::PEM_encode(priv));
++#else
+ if ((*maybe_passphrase)().length())
+ Botan::PKCS8::encrypt_key(priv, *unfiltered_pipe,
+ #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
+@@ -710,13 +733,20 @@ key_store::create_key_pair(database & db,
+ Botan::RAW_BER);
+ else
+ Botan::PKCS8::encode(priv, *unfiltered_pipe);
++#endif
+ unfiltered_pipe->end_msg();
+- kp.priv = rsa_priv_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE),
+- origin::internal);
++
++ kp.priv = rsa_priv_key(
++ unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE),
++ origin::internal);
+
+ // serialize the public key
+ unfiltered_pipe->start_msg();
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,10,0)
++ unfiltered_pipe->write(Botan::X509::BER_encode(priv));
++#else
+ Botan::X509::encode(priv, *unfiltered_pipe, Botan::RAW_BER);
++#endif
+ unfiltered_pipe->end_msg();
+ kp.pub = rsa_pub_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE),
+ origin::internal);
+@@ -783,6 +813,15 @@ key_store::change_key_passphrase(key_id const & id)
+ get_passphrase(new_phrase, name, id, true, false);
+
+ unfiltered_pipe->start_msg();
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,10,0)
++ if (new_phrase().length())
++ unfiltered_pipe->write(
++ Botan::PKCS8::BER_encode(*priv, lazy_rng::get(),
++ new_phrase(),
++ "PBE-PKCS5v20(SHA-1,TripleDES/CBC)"));
++ else
++ unfiltered_pipe->write(Botan::PKCS8::PEM_encode(*priv));
++#else
+ if (new_phrase().length())
+ Botan::PKCS8::encrypt_key(*priv, *unfiltered_pipe,
+ #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
+@@ -793,6 +832,7 @@ key_store::change_key_passphrase(key_id const & id)
+ Botan::RAW_BER);
+ else
+ Botan::PKCS8::encode(*priv, *unfiltered_pipe);
++#endif
+
+ unfiltered_pipe->end_msg();
+ kp.priv = rsa_priv_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE),
+@@ -813,19 +853,32 @@ key_store::decrypt_rsa(key_id const & id,
+ load_key_pair(*this, id, kp);
+ shared_ptr<RSA_PrivateKey> priv_key = s->decrypt_private_key(id);
+
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,10,0)
++ Botan::PK_Decryptor_EME decryptor(*priv_key, "EME1(SHA-1)");
++
++ SecureVector<byte> plain =
++ decryptor.decrypt(reinterpret_cast<byte const *>(ciphertext().data()),
++ ciphertext().size());
++ plaintext = string(plain.begin(), plain.end());
++#else
+ shared_ptr<PK_Decryptor>
+- decryptor(get_pk_decryptor(*priv_key, "EME1(SHA-1)"));
++ decryptor(Botan::get_pk_decryptor(*priv_key, "EME1(SHA-1)"));
+
+- SecureVector<Botan::byte> plain =
+- decryptor->decrypt(reinterpret_cast<Botan::byte const *>(ciphertext().data()),
++ SecureVector<byte> plain =
++ decryptor->decrypt(reinterpret_cast<byte const *>(ciphertext().data()),
+ ciphertext().size());
+ plaintext = string(reinterpret_cast<char const*>(plain.begin()),
+ plain.size());
++#endif
+ }
+- catch (Botan::Exception & ex)
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,4)
++ catch (std::exception & e)
++#else
++ catch (Botan::Exception & e)
++#endif
+ {
+ E(false, ciphertext.made_from,
+- F("Botan error decrypting data: '%s'") % ex.what());
++ F("Botan error decrypting data: '%s'") % e.what());
+ }
+ }
+
+@@ -856,9 +909,9 @@ key_store::make_signature(database & db,
+ {
+ if (agent.connected()) {
+ //grab the monotone public key as an RSA_PublicKey
+- SecureVector<Botan::byte> pub_block;
+- pub_block.set(reinterpret_cast<Botan::byte const *>(key.pub().data()),
+- key.pub().size());
++ SecureVector<byte> pub_block
++ (reinterpret_cast<byte const *>(key.pub().data()),
++ key.pub().size());
+ L(FL("make_signature: building %d-byte pub key") % pub_block.size());
+ shared_ptr<X509_PublicKey> x509_key =
+ shared_ptr<X509_PublicKey>(Botan::X509::load_key(pub_block));
+@@ -884,7 +937,7 @@ key_store::make_signature(database & db,
+ || s->ssh_sign_mode == "check"
+ || s->ssh_sign_mode == "no")
+ {
+- SecureVector<Botan::byte> sig;
++ SecureVector<byte> sig;
+
+ // we permit the user to relax security here, by caching a decrypted key
+ // (if they permit it) through the life of a program run. this helps when
+@@ -908,7 +961,13 @@ key_store::make_signature(database & db,
+ L(FL("make_signature: adding private key (%s) to ssh-agent") % id);
+ agent.add_identity(*priv_key, name());
+ }
+- signer = shared_ptr<PK_Signer>(get_pk_signer(*priv_key, "EMSA3(SHA-1)"));
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,10,0)
++ signer = shared_ptr<PK_Signer>(
++ new PK_Signer(*priv_key, "EMSA3(SHA-1)"));
++#else
++ signer = shared_ptr<PK_Signer>(
++ get_pk_signer(*priv_key, "EMSA3(SHA-1)"));
++#endif
+
+ /* If persist_phrase is true, the RSA_PrivateKey object is
+ cached in s->active_keys and will survive as long as the
+@@ -919,11 +978,11 @@ key_store::make_signature(database & db,
+
+ #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
+ sig = signer->sign_message(
+- reinterpret_cast<Botan::byte const *>(tosign.data()),
++ reinterpret_cast<byte const *>(tosign.data()),
+ tosign.size(), lazy_rng::get());
+ #else
+ sig = signer->sign_message(
+- reinterpret_cast<Botan::byte const *>(tosign.data()),
++ reinterpret_cast<byte const *>(tosign.data()),
+ tosign.size());
+ #endif
+ sig_string = string(reinterpret_cast<char const*>(sig.begin()), sig.size());
+@@ -988,6 +1047,15 @@ key_store::export_key_for_agent(key_id const & id,
+ // This pipe cannot sensibly be recycled.
+ Pipe p(new Botan::DataSink_Stream(os));
+ p.start_msg();
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,10,0)
++ if (new_phrase().length())
++ p.write(Botan::PKCS8::PEM_encode(*priv,
++ lazy_rng::get(),
++ new_phrase(),
++ "PBE-PKCS5v20(SHA-1,TripleDES/CBC)"));
++ else
++ p.write(Botan::PKCS8::PEM_encode(*priv));
++#else
+ if (new_phrase().length())
+ Botan::PKCS8::encrypt_key(*priv,
+ p,
+@@ -998,6 +1066,7 @@ key_store::export_key_for_agent(key_id const & id,
+ "PBE-PKCS5v20(SHA-1,TripleDES/CBC)");
+ else
+ Botan::PKCS8::encode(*priv, p);
++#endif
+ p.end_msg();
+ }
+
+@@ -1013,7 +1082,7 @@ key_store_state::migrate_old_key_pair
+ rsa_pub_key const & pub)
+ {
+ keypair kp;
+- SecureVector<Botan::byte> arc4_key;
++ SecureVector<byte> arc4_key;
+ utf8 phrase;
+ shared_ptr<PKCS8_PrivateKey> pkcs8_key;
+ shared_ptr<RSA_PrivateKey> priv_key;
+@@ -1031,8 +1100,14 @@ key_store_state::migrate_old_key_pair
+ for (;;)
+ try
+ {
+- arc4_key.set(reinterpret_cast<Botan::byte const *>(phrase().data()),
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++ arc4_key.resize(phrase().size());
++ arc4_key.copy(reinterpret_cast<byte const *>(phrase().data()),
++ phrase().size());
++#else
++ arc4_key.set(reinterpret_cast<byte const *>(phrase().data()),
+ phrase().size());
++#endif
+
+ Pipe arc4_decryptor(get_cipher("ARC4", arc4_key, Botan::DECRYPTION));
+
+@@ -1041,7 +1116,7 @@ key_store_state::migrate_old_key_pair
+ // This is necessary because PKCS8::load_key() cannot currently
+ // recognize an unencrypted, raw-BER blob as such, but gets it
+ // right if it's PEM-coded.
+- SecureVector<Botan::byte> arc4_decrypt(arc4_decryptor.read_all());
++ SecureVector<byte> arc4_decrypt(arc4_decryptor.read_all());
+ Botan::DataSource_Memory ds(Botan::PEM_Code::encode(arc4_decrypt,
+ "PRIVATE KEY"));
+ #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
+@@ -1051,7 +1126,11 @@ key_store_state::migrate_old_key_pair
+ #endif
+ break;
+ }
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,4)
++ catch (Botan::Invalid_Argument & e)
++#else
+ catch (Botan::Exception & e)
++#endif
+ {
+ L(FL("migrate_old_key_pair: failure %d to load old private key: %s")
+ % cycles % e.what());
+@@ -1070,6 +1149,11 @@ key_store_state::migrate_old_key_pair
+
+ // now we can write out the new key
+ unfiltered_pipe->start_msg();
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,10,0)
++ unfiltered_pipe->write(Botan::PKCS8::BER_encode(
++ *priv_key, lazy_rng::get(), phrase(),
++ "PBE-PKCS5v20(SHA-1,TripleDES/CBC)"));
++#else
+ Botan::PKCS8::encrypt_key(*priv_key, *unfiltered_pipe,
+ #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
+ lazy_rng::get(),
+@@ -1077,6 +1161,7 @@ key_store_state::migrate_old_key_pair
+ phrase(),
+ "PBE-PKCS5v20(SHA-1,TripleDES/CBC)",
+ Botan::RAW_BER);
++#endif
+ unfiltered_pipe->end_msg();
+ kp.priv = rsa_priv_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE),
+ origin::internal);
+@@ -1085,7 +1170,11 @@ key_store_state::migrate_old_key_pair
+ // Botan for the X.509 encoding of the private key implies that we want
+ // it to derive and produce the public key)
+ unfiltered_pipe->start_msg();
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,10,0)
++ unfiltered_pipe->write(Botan::X509::BER_encode(*priv_key));
++#else
+ Botan::X509::encode(*priv_key, *unfiltered_pipe, Botan::RAW_BER);
++#endif
+ unfiltered_pipe->end_msg();
+ kp.pub = rsa_pub_key(unfiltered_pipe->read_all_as_string(Pipe::LAST_MESSAGE),
+ origin::internal);
+diff --git a/src/monotone.cc b/src/monotone.cc
+index 281e940..f2c844a 100644
+--- a/src/monotone.cc
++++ b/src/monotone.cc
+@@ -156,27 +156,53 @@ cpp_main(int argc, char ** argv)
+ E(linked_botan_version != BOTAN_VERSION_CODE_FOR(1,7,14), origin::system,
+ F("monotone does not support Botan 1.7.14"));
+
+-#if BOTAN_VERSION_CODE <= BOTAN_VERSION_CODE_FOR(1,7,6)
++ // In Botan 1.9.9, the DataSink_Stream cannot be instantiated per
++ // se. As 1.10.1 is already out, let's simply disable support for
++ // that specific (testing) version of botan.
++ E(linked_botan_version != BOTAN_VERSION_CODE_FOR(1,9,9), origin::system,
++ F("monotone does not support Botan 1.9.9"));
++
++#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,7,7)
++ // motonote binary compiled against botan younger than 1.7.7
+ E(linked_botan_version >= BOTAN_VERSION_CODE_FOR(1,6,3), origin::system,
+ F("this monotone binary requires Botan 1.6.3 or newer"));
+- E(linked_botan_version <= BOTAN_VERSION_CODE_FOR(1,7,6), origin::system,
+- F("this monotone binary does not work with Botan newer than 1.7.6"));
+-#elif BOTAN_VERSION_CODE <= BOTAN_VERSION_CODE_FOR(1,7,22)
+- E(linked_botan_version > BOTAN_VERSION_CODE_FOR(1,7,6), origin::system,
++ E(linked_botan_version < BOTAN_VERSION_CODE_FOR(1,7,7), origin::system,
++ F("this monotone binary does not work with Botan 1.7.7 or newer"));
++
++#elif BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,7,22)
++ // motonote binary compiled against botan 1.7.7 - 1.7.21
++ E(linked_botan_version >= BOTAN_VERSION_CODE_FOR(1,7,7), origin::system,
+ F("this monotone binary requires Botan 1.7.7 or newer"));
+- // While compiling against 1.7.22 or newer is recommended, because
+- // it enables new features of Botan, the monotone binary compiled
+- // against Botan 1.7.21 and before should still work with newer Botan
+- // versions, including all of the stable branch 1.8.x.
+- E(linked_botan_version < BOTAN_VERSION_CODE_FOR(1,9,0), origin::system,
+- F("this monotone binary does not work with Botan 1.9.x"));
+-#else
+- E(linked_botan_version > BOTAN_VERSION_CODE_FOR(1,7,22), origin::system,
++ // While compiling against 1.7.22 or newer is recommended, because it
++ // enables new features of Botan, the monotone binary compiled against
++ // Botan 1.7.21 and before should still work with newer Botan version,
++ // including all of the stable branch 1.8.x, up to and including
++ // 1.9.3.
++ E(linked_botan_version < BOTAN_VERSION_CODE_FOR(1,9,4), origin::system,
++ F("this monotone binary does not work with Botan 1.9.4 or newer"));
++
++#elif BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,9,4)
++ // motonote binary compiled against botan 1.7.22 - 1.9.3
++ E(linked_botan_version >= BOTAN_VERSION_CODE_FOR(1,7,22), origin::system,
+ F("this monotone binary requires Botan 1.7.22 or newer"));
+- E(linked_botan_version < BOTAN_VERSION_CODE_FOR(1,9,0), origin::system,
+- F("this monotone binary does not work with Botan 1.9.x"));
++ E(linked_botan_version < BOTAN_VERSION_CODE_FOR(1,9,4), origin::system,
++ F("this monotone binary does not work with Botan 1.9.4 or newer"));
++
++#elif BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,9,11)
++ // motonote binary compiled against botan 1.9.4 - 1.9.10
++#pragma message ( "The resulting monotone binary won't be able to run with any stable release of botan." )
++ E(linked_botan_version >= BOTAN_VERSION_CODE_FOR(1,9,4), origin::system,
++ F("this monotone binary requires Botan 1.9.4 or newer"));
++ E(linked_botan_version < BOTAN_VERSION_CODE_FOR(1,9,11), origin::system,
++ F("this monotone binary does not work with Botan 1.9.11 or newer"));
++
++#else
++ // motonote binary compiled against botan 1.9.11 and newer
++ E(linked_botan_version >= BOTAN_VERSION_CODE_FOR(1,9,11), origin::system,
++ F("this monotone binary requires Botan 1.9.11 or newer"));
+ #endif
+
++
+ app_state app;
+ try
+ {
+diff --git a/src/packet.cc b/src/packet.cc
+index 87ff24a..f592d50 100644
+--- a/src/packet.cc
++++ b/src/packet.cc
+@@ -156,8 +156,8 @@ namespace
+ void validate_public_key_data(string const & name, string const & keydata) const
+ {
+ string decoded = decode_base64_as<string>(keydata, origin::user);
+- Botan::SecureVector<Botan::byte> key_block;
+- key_block.set(reinterpret_cast<Botan::byte const *>(decoded.c_str()), decoded.size());
++ Botan::SecureVector<Botan::byte> key_block
++ (reinterpret_cast<Botan::byte const *>(decoded.c_str()), decoded.size());
+ try
+ {
+ Botan::X509::load_key(key_block);
+@@ -175,7 +175,9 @@ namespace
+ Botan::DataSource_Memory ds(decoded);
+ try
+ {
+-#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++ Botan::PKCS8::load_key(ds, lazy_rng::get(), Dummy_UI());
++#elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,7,7)
+ Botan::PKCS8::load_key(ds, lazy_rng::get(), string());
+ #else
+ Botan::PKCS8::load_key(ds, string());
+@@ -189,7 +191,11 @@ namespace
+ }
+ // since we do not want to prompt for a password to decode it finally,
+ // we ignore all other exceptions
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++ catch (Passphrase_Required) {}
++#else
+ catch (Botan::Invalid_Argument) {}
++#endif
+ }
+ void validate_certname(string const & cn) const
+ {
+@@ -460,7 +466,15 @@ read_packets(istream & in, packet_consumer & cons)
+ return count;
+ }
+
+-
++// Dummy User_Interface implementation for Botan
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++std::string
++Dummy_UI::get_passphrase(const std::string &, const std::string &,
++ Botan::User_Interface::UI_Result&) const
++{
++ throw Passphrase_Required("Passphrase required");
++}
++#endif
+
+ // Local Variables:
+ // mode: C++
+diff --git a/src/packet.hh b/src/packet.hh
+index 239f996..3d5c1b5 100644
+--- a/src/packet.hh
++++ b/src/packet.hh
+@@ -10,6 +10,10 @@
+ #ifndef __PACKET_HH__
+ #define __PACKET_HH__
+
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++#include <botan/ui.h>
++#endif
++
+ #include "vocab.hh"
+
+ struct cert;
+@@ -84,6 +88,21 @@ struct packet_writer : public packet_consumer
+
+ size_t read_packets(std::istream & in, packet_consumer & cons);
+
++#if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,11)
++// A helper class implementing Botan::User_Interface - which doesn't really
++// interface with the user, but provides the necessary plumbing for Botan.
++//
++// See Botan commit 2d09d7d0cd4bd0e7155d001dd65a4f29103b158c
++typedef std::runtime_error Passphrase_Required;
++
++class Dummy_UI : public Botan::User_Interface
++{
++public:
++ virtual std::string get_passphrase(const std::string &, const std::string &,
++ Botan::User_Interface::UI_Result &) const;
++};
++#endif
++
+ #endif
+
+ // Local Variables:
+diff --git a/src/sha1.cc b/src/sha1.cc
+index d4d7232..5f47f90 100644
+--- a/src/sha1.cc
++++ b/src/sha1.cc
+@@ -50,9 +50,12 @@ CMD_HIDDEN(benchmark_sha1, "benchmark_sha1", "", CMD_REF(debug), "",
+ Botan::Default_Benchmark_Timer timer;
+ std::map<std::string, double> results =
+ Botan::algorithm_benchmark("SHA-1", milliseconds, timer, rng, af);
+-#else
++#elif BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,9,11)
+ std::map<std::string, double> results =
+ Botan::algorithm_benchmark("SHA-1", milliseconds, rng, af);
++#else
++ std::map<std::string, double> results =
++ Botan::algorithm_benchmark("SHA-1", af, rng, milliseconds, 16);
+ #endif
+
+ for(std::map<std::string, double>::const_iterator i = results.begin();
+diff --git a/src/ssh_agent.cc b/src/ssh_agent.cc
+index 157f59a..051e2f7 100644
+--- a/src/ssh_agent.cc
++++ b/src/ssh_agent.cc
+@@ -385,9 +385,9 @@ bool
+ ssh_agent::has_key(const keypair & key)
+ {
+ //grab the monotone public key as an RSA_PublicKey
+- SecureVector<Botan::byte> pub_block;
+- pub_block.set(reinterpret_cast<Botan::byte const *>((key.pub)().data()),
+- (key.pub)().size());
++ SecureVector<Botan::byte> pub_block
++ (reinterpret_cast<Botan::byte const *>((key.pub)().data()),
++ (key.pub)().size());
+ L(FL("has_key: building %d-byte pub key") % pub_block.size());
+ shared_ptr<X509_PublicKey> x509_key =
+ shared_ptr<X509_PublicKey>(Botan::X509::load_key(pub_block));
+diff --git a/src/transforms.cc b/src/transforms.cc
+index e4d9443..546d5ab 100644
+--- a/src/transforms.cc
++++ b/src/transforms.cc
+@@ -53,15 +53,16 @@ using Botan::Hash_Filter;
+ // paradigm "must" be used. this program is intended for source code
+ // control and I make no bones about it.
+
+-NORETURN(static inline void error_in_transform(Botan::Exception & e));
++NORETURN(static inline void error_in_transform(std::exception & e));
+
+ static inline void
+-error_in_transform(Botan::Exception & e, origin::type caused_by)
++error_in_transform(std::exception & e, origin::type caused_by)
+ {
+ // these classes can all indicate data corruption
+ if (typeid(e) == typeid(Botan::Encoding_Error)
+ || typeid(e) == typeid(Botan::Decoding_Error)
+ || typeid(e) == typeid(Botan::Stream_IO_Error)
++ || typeid(e) == typeid(Botan::Invalid_Argument)
+ || typeid(e) == typeid(Botan::Integrity_Failure))
+ {
+ // clean up the what() string a little: throw away the
+@@ -107,7 +108,7 @@ error_in_transform(Botan::Exception & e, origin::type caused_by)
+ pipe->process_msg(in); \
+ out = pipe->read_all_as_string(Pipe::LAST_MESSAGE); \
+ } \
+- catch (Botan::Exception & e) \
++ catch (std::exception & e) \
+ { \
+ pipe.reset(new Pipe(new T(carg))); \
+ error_in_transform(e, made_from); \
+@@ -173,7 +174,7 @@ template<> string xform<Botan::Hex_Decoder>(string const & in,
+ {
+ throw Botan::Decoding_Error(string("invalid hex character '") + (char)c + "'");
+ }
+- catch(Botan::Exception & e)
++ catch(std::exception & e)
+ {
+ error_in_transform(e, made_from);
+ }
+@@ -219,7 +220,7 @@ void pack(T const & in, base64< gzip<T> > & out)
+ tmp = pipe->read_all_as_string(Pipe::LAST_MESSAGE);
+ out = base64< gzip<T> >(tmp, in.made_from);
+ }
+- catch (Botan::Exception & e)
++ catch (std::exception & e)
+ {
+ pipe.reset(new Pipe(new Gzip_Compression,
+ new Base64_Encoder));
+@@ -237,7 +238,7 @@ void unpack(base64< gzip<T> > const & in, T & out)
+ pipe->process_msg(in());
+ out = T(pipe->read_all_as_string(Pipe::LAST_MESSAGE), in.made_from);
+ }
+- catch (Botan::Exception & e)
++ catch (std::exception & e)
+ {
+ pipe.reset(new Pipe(new Base64_Decoder,
+ new Gzip_Decompression));
+@@ -264,7 +265,7 @@ calculate_ident(data const & dat,
+ p->process_msg(dat());
+ ident = id(p->read_all_as_string(Pipe::LAST_MESSAGE), dat.made_from);
+ }
+- catch (Botan::Exception & e)
++ catch (std::exception & e)
+ {
+ p.reset(new Pipe(new Hash_Filter("SHA-160")));
+ error_in_transform(e, dat.made_from);
+--
+tg: (1150daa..) t/botan-1.10 (depends on: master)
diff --git a/monotone-1.0-fix-texinfo.patch b/monotone-1.0-fix-texinfo.patch
new file mode 100644
index 0000000..6a4e1ec
--- /dev/null
+++ b/monotone-1.0-fix-texinfo.patch
@@ -0,0 +1,623 @@
+Description: fix texinfo errors with texinfo >= 5.0
+Origin: upstream, commit: 0d22697daf2fd169db15445cd88f8a7be7371f64
+Author: Markus Wanner <markus at bluegap.ch>
+--- a/doc/monotone.texi
++++ b/doc/monotone.texi
+@@ -4779,7 +4779,7 @@
+ Cancel all previous @option{--rcfile} options (standard rcfiles are
+ still loaded). See @ref{rcfiles}.
+
+- at itemx --root <arg>
++ at item --root <arg>
+ Limit the search for a workspace to the specified root directory
+
+ @item --ssh-sign <arg>
+@@ -6150,7 +6150,7 @@
+ Specifying only the pathname "." will restrict the search for unknown
+ files to the current subdirectory of the workspace.
+
+- at itemx mtn list vars [@var{domain}]
++ at item mtn list vars [@var{domain}]
+ @itemx mtn ls vars
+ @command{ls vars} is an alias for @command{list vars}.
+
+--- a/doc/pcrepattern.texi
++++ b/doc/pcrepattern.texi
+@@ -74,32 +74,32 @@
+ brackets, the metacharacters are as follows:
+
+ @table @code
+- at itemx \
++ at item \
+ general escape character with several uses
+- at itemx ^
++ at item ^
+ assert start of string (or line, in multiline mode)
+- at itemx $
++ at item $
+ assert end of string (or line, in multiline mode)
+- at itemx .
++ at item .
+ match any character except newline (by default)
+- at itemx [
++ at item [
+ start character class definition
+- at itemx |
++ at item |
+ start of alternative branch
+- at itemx (
++ at item (
+ start subpattern
+- at itemx )
++ at item )
+ end subpattern
+- at itemx ?
++ at item ?
+ extends the meaning of @samp{(}
+ also 0 or 1 quantifier
+ also quantifier minimizer
+- at itemx *
++ at item *
+ 0 or more quantifier
+- at itemx +
++ at item +
+ 1 or more quantifier
+ also ``possessive quantifier''
+- at itemx @{
++ at item @{
+ start min/max quantifier
+ @end table
+
+@@ -108,16 +108,16 @@
+ class". In a character class the only metacharacters are:
+
+ @table @code
+- at itemx \
++ at item \
+ general escape character
+- at itemx ^
++ at item ^
+ negate the class, but only if the first character
+- at itemx -
++ at item -
+ indicates character range
+- at itemx [
++ at item [
+ POSIX character class (only if followed by POSIX
+ syntax)
+- at itemx ]
++ at item ]
+ terminates the character class
+ @end table
+
+@@ -159,25 +159,25 @@
+ represents:
+
+ @table @code
+- at itemx \a
++ at item \a
+ alarm, that is, the BEL character (hex 07)
+- at itemx \c at var{x}
++ at item \c at var{x}
+ "control- at var{x}", where @var{x} is any character
+- at itemx \e
++ at item \e
+ escape (hex 1B)
+- at itemx \f
++ at item \f
+ formfeed (hex 0C)
+- at itemx \n
++ at item \n
+ linefeed (hex 0A)
+- at itemx \r
++ at item \r
+ carriage return (hex 0D)
+- at itemx \t
++ at item \t
+ tab (hex 09)
+- at itemx \@var{ddd}
++ at item \@var{ddd}
+ character with octal code @var{ddd}, or backreference
+- at itemx \x at var{hh}
++ at item \x at var{hh}
+ character with hex code @var{hh}
+- at itemx \x@{@var{hhh...}@}
++ at item \x@{@var{hhh...}@}
+ character with hex code @var{hhh...}
+ @end table
+
+@@ -244,27 +244,27 @@
+ @samp{\777} are permitted. For example:
+
+ @table @code
+- at itemx \040
++ at item \040
+ is another way of writing a space
+- at itemx \40
++ at item \40
+ is the same, provided there are fewer than 40
+ previous capturing subpatterns
+- at itemx \7
++ at item \7
+ is always a back reference
+- at itemx \11
++ at item \11
+ might be a back reference, or another way of
+ writing a tab
+- at itemx \011
++ at item \011
+ is always a tab
+- at itemx \0113
++ at item \0113
+ is a tab followed by the character @samp{3}
+- at itemx \113
++ at item \113
+ might be a back reference, otherwise the
+ character with octal code 113
+- at itemx \377
++ at item \377
+ might be a back reference, otherwise
+ the byte consisting entirely of 1 bits
+- at itemx \81
++ at item \81
+ is either a back reference, or a binary zero
+ followed by the two characters @samp{8} and @samp{1}
+ @end table
+@@ -294,25 +294,25 @@
+ following are always recognized:
+
+ @table @code
+- at itemx \d
++ at item \d
+ any decimal digit
+- at itemx \D
++ at item \D
+ any character that is not a decimal digit
+- at itemx \h
++ at item \h
+ any horizontal whitespace character
+- at itemx \H
++ at item \H
+ any character that is not a horizontal whitespace character
+- at itemx \s
++ at item \s
+ any whitespace character
+- at itemx \S
++ at item \S
+ any character that is not a whitespace character
+- at itemx \v
++ at item \v
+ any vertical whitespace character
+- at itemx \V
++ at item \V
+ any character that is not a vertical whitespace character
+- at itemx \w
++ at item \w
+ any ``word'' character
+- at itemx \W
++ at item \W
+ any ``non-word'' character
+ @end table
+
+@@ -342,43 +342,43 @@
+ characters are:
+
+ @table @code
+- at itemx U+0009
++ at item U+0009
+ Horizontal tab
+- at itemx U+0020
++ at item U+0020
+ Space
+- at itemx U+00A0
++ at item U+00A0
+ Non-break space
+- at itemx U+1680
++ at item U+1680
+ Ogham space mark
+- at itemx U+180E
++ at item U+180E
+ Mongolian vowel separator
+ @item U+2000
+ En quad
+- at itemx U+2001
++ at item U+2001
+ Em quad
+- at itemx U+2002
++ at item U+2002
+ En space
+- at itemx U+2003
++ at item U+2003
+ Em space
+- at itemx U+2004
++ at item U+2004
+ Three-per-em space
+- at itemx U+2005
++ at item U+2005
+ Four-per-em space
+- at itemx U+2006
++ at item U+2006
+ Six-per-em space
+ @item U+2007
+ Figure space
+- at itemx U+2008
++ at item U+2008
+ Punctuation space
+- at itemx U+2009
++ at item U+2009
+ Thin space
+- at itemx U+200A
++ at item U+200A
+ Hair space
+- at itemx U+202F
++ at item U+202F
+ Narrow no-break space
+- at itemx U+205F
++ at item U+205F
+ Medium mathematical space
+- at itemx U+3000
++ at item U+3000
+ Ideographic space
+ @end table
+
+@@ -386,19 +386,19 @@
+ The vertical space characters are:
+
+ @table @code
+- at itemx U+000A
++ at item U+000A
+ Linefeed
+- at itemx U+000B
++ at item U+000B
+ Vertical tab
+- at itemx U+000C
++ at item U+000C
+ Formfeed
+- at itemx U+000D
++ at item U+000D
+ Carriage return
+- at itemx U+0085
++ at item U+0085
+ Next line
+- at itemx U+2028
++ at item U+2028
+ Line separator
+- at itemx U+2029
++ at item U+2029
+ Paragraph separator
+ @end table
+
+@@ -418,15 +418,15 @@
+ the following five sequences:
+
+ @table @code
+- at itemx (*CR)
++ at item (*CR)
+ carriage return
+- at itemx (*LF)
++ at item (*LF)
+ linefeed
+- at itemx (*CRLF)
++ at item (*CRLF)
+ carriage return, followed by linefeed
+- at itemx (*ANYCRLF)
++ at item (*ANYCRLF)
+ any of the three above
+- at itemx (*ANY)
++ at item (*ANY)
+ all Unicode newline sequences
+ @end table
+
+@@ -474,9 +474,9 @@
+ pattern string with one of the following sequences:
+
+ @table @code
+- at itemx (*BSR_ANYCRLF)
++ at item (*BSR_ANYCRLF)
+ @key{CR}, @key{LF}, or @key{CR}@key{LF} only
+- at itemx (*BSR_UNICODE)
++ at item (*BSR_UNICODE)
+ any Unicode newline sequence (the default)
+ @end table
+
+@@ -501,11 +501,11 @@
+ 256, but they do work in this mode. The extra escape sequences are:
+
+ @table @code
+- at itemx \p@{@var{xx}@}
++ at item \p@{@var{xx}@}
+ a character with the @var{xx} property
+- at itemx \P@{@var{xx}@}
++ at item \P@{@var{xx}@}
+ a character without the @var{xx} property
+- at itemx \X
++ at item \X
+ an extended Unicode sequence
+ @end table
+
+@@ -618,83 +618,83 @@
+ @table @code
+ @item C
+ Other
+- at itemx Cc
++ at item Cc
+ Control
+- at itemx Cf
++ at item Cf
+ Format
+- at itemx Cn
++ at item Cn
+ Unassigned
+- at itemx Co
++ at item Co
+ Private use
+- at itemx Cs
++ at item Cs
+ Surrogate
+
+ @item L
+ Letter
+- at itemx Ll
++ at item Ll
+ Lower case letter
+- at itemx Lm
++ at item Lm
+ Modifier letter
+- at itemx Lo
++ at item Lo
+ Other letter
+- at itemx Lt
++ at item Lt
+ Title case letter
+- at itemx Lu
++ at item Lu
+ Upper case letter
+
+ @item M
+ Mark
+- at itemx Mc
++ at item Mc
+ Spacing mark
+- at itemx Me
++ at item Me
+ Enclosing mark
+- at itemx Mn
++ at item Mn
+ Non-spacing mark
+
+ @item N
+ Number
+- at itemx Nd
++ at item Nd
+ Decimal number
+- at itemx Nl
++ at item Nl
+ Letter number
+- at itemx No
++ at item No
+ Other number
+
+ @item P
+ Punctuation
+- at itemx Pc
++ at item Pc
+ Connector punctuation
+- at itemx Pd
++ at item Pd
+ Dash punctuation
+- at itemx Pe
++ at item Pe
+ Close punctuation
+- at itemx Pf
++ at item Pf
+ Final punctuation
+- at itemx Pi
++ at item Pi
+ Initial punctuation
+- at itemx Po
++ at item Po
+ Other punctuation
+- at itemx Ps
++ at item Ps
+ Open punctuation
+
+ @item S
+ Symbol
+- at itemx Sc
++ at item Sc
+ Currency symbol
+- at itemx Sk
++ at item Sk
+ Modifier symbol
+- at itemx Sm
++ at item Sm
+ Mathematical symbol
+- at itemx So
++ at item So
+ Other symbol
+
+ @item Z
+ Separator
+- at itemx Zl
++ at item Zl
+ Line separator
+- at itemx Zp
++ at item Zp
+ Paragraph separator
+- at itemx Zs
++ at item Zs
+ Space separator
+ @end table
+
+@@ -771,18 +771,18 @@
+ described below. The backslashed assertions are:
+
+ @table @code
+- at itemx \b
++ at item \b
+ matches at a word boundary
+- at itemx \B
++ at item \B
+ matches when not at a word boundary
+- at itemx \A
++ at item \A
+ matches at the start of the subject
+- at itemx \Z
++ at item \Z
+ matches at the end of the subject
+ also matches before a newline at the end of the subject
+- at itemx \z
++ at item \z
+ matches only at the end of the subject
+- at itemx \G
++ at item \G
+ matches at the first matching position in the subject
+ @end table
+
+@@ -993,33 +993,33 @@
+ supported class names are
+
+ @table @code
+- at itemx alnum
++ at item alnum
+ letters and digits
+- at itemx alpha
++ at item alpha
+ letters
+- at itemx ascii
++ at item ascii
+ character codes 0 -- 127
+- at itemx blank
++ at item blank
+ space or tab only
+- at itemx cntrl
++ at item cntrl
+ control characters
+- at itemx digit
++ at item digit
+ decimal digits (same as @samp{\d})
+- at itemx graph
++ at item graph
+ printing characters, excluding space
+- at itemx lower
++ at item lower
+ lower case letters
+- at itemx print
++ at item print
+ printing characters, including space
+- at itemx punct
++ at item punct
+ printing characters, excluding letters and digits
+- at itemx space
++ at item space
+ white space (not quite the same as @samp{\s})
+- at itemx upper
++ at item upper
+ upper case letters
+- at itemx word
++ at item word
+ ``word'' characters (same as @samp{\w})
+- at itemx xdigit
++ at item xdigit
+ hexadecimal digits
+ @end table
+
+@@ -1071,22 +1071,22 @@
+ @samp{)}. The option letters are
+
+ @table @code
+- at itemx i
++ at item i
+ Caseless: characters in one case match the corresponding
+ characters in other cases as well.
+- at itemx m
++ at item m
+ Multiline: @samp{^} and @samp{$} match at newlines
+ as well as at beginning and end of string.
+- at itemx s
++ at item s
+ Dotall: dot matches any character, including newline characters.
+- at itemx x
++ at item x
+ Extended syntax: unescaped white space is ignored and embedded
+ comments are possible.
+- at itemx J
++ at item J
+ Dupnames: names for capturing subpattern need not be unique.
+- at itemx U
++ at item U
+ Ungreedy: quantifiers match as few times as possible by default.
+- at itemx X
++ at item X
+ Extra: for forward compatibility, give an error if any escape sequence
+ with no defined meaning appears.
+ @end table
+@@ -1358,11 +1358,11 @@
+ single-character abbreviations:
+
+ @table @code
+- at itemx *
++ at item *
+ is equivalent to @{0,@}
+- at itemx +
++ at item +
+ is equivalent to @{1,@}
+- at itemx ?
++ at item ?
+ is equivalent to @{0,1@}
+ @end table
+
+@@ -2302,7 +2302,7 @@
+ The following verbs act as soon as they are encountered:
+
+ @table @code
+- at itemx (*ACCEPT)
++ at item (*ACCEPT)
+
+ This verb causes the match to end successfully, skipping the remainder
+ of the pattern. When inside a recursion, only the innermost pattern is
+@@ -2317,7 +2317,7 @@
+ This matches @samp{AB}, @samp{AAD}, or @samp{ACD}, but when it matches
+ @samp{AB}, no data is captured.
+
+- at itemx (*FAIL) @r{or} (*F)
++ at item (*FAIL) @r{or} (*F)
+
+ This verb causes the match to fail, forcing backtracking to occur. It
+ is equivalent to @samp{(?!)} but easier to read. It is not clear
+@@ -2334,7 +2334,7 @@
+ occurs.
+
+ @table @code
+- at itemx (*COMMIT)
++ at item (*COMMIT)
+
+ This verb causes the whole match to fail outright if the rest of the
+ pattern does not match. Even if the pattern is unanchored, no further
+@@ -2350,7 +2350,7 @@
+ This matches @samp{xxaab} but not @samp{aacaab}. It can be thought of
+ as a kind of dynamic anchor, or ``I've started, so I must finish.''
+
+- at itemx (*PRUNE)
++ at item (*PRUNE)
+
+ This verb causes the match to fail at the current position if the rest
+ of the pattern does not match. If the pattern is unanchored, the
+@@ -2363,7 +2363,7 @@
+ are some uses of @code{(*PRUNE)} that cannot be expressed in any other
+ way.
+
+- at itemx (*SKIP)
++ at item (*SKIP)
+
+ This verb is like @code{(*PRUNE)}, except that if the pattern is
+ unanchored, the "bumpalong" advance is not to the next character, but
+@@ -2383,7 +2383,7 @@
+ attempt would start at the second character instead of skipping on to
+ @samp{c}.
+
+- at itemx (*THEN)
++ at item (*THEN)
+
+ This verb causes a skip to the next alternation if the rest of the
+ pattern does not match. That is, it cancels pending backtracking, but
diff --git a/monotone-1.0-lua-5.2.patch b/monotone-1.0-lua-5.2.patch
new file mode 100644
index 0000000..2493490
--- /dev/null
+++ b/monotone-1.0-lua-5.2.patch
@@ -0,0 +1,752 @@
+From: Thomas Moschny <thomas.moschny at gmx.de>
+Subject: [PATCH] lua-5.2
+
+Support Lua 5.2.
+
+Apply patches from these upstream commits:
+53e02eaa302bc05e96a18e3882b0e9843b53cf9a (partially)
+fd98d953ca93454c66a55aadf2adbeb87de86f69 (with some tweaking)
+fe1180f754da5d552c308b61e8129e59039bc559
+
+---
+ extra/mtn-hooks/monotone-cvs-ignore.lua | 2 +-
+ src/lua.cc | 40 +++++++++++---
+ src/lua.hh | 14 ++---
+ src/luaext_parse_basic_io.cc | 4 ++
+ src/luaext_platform.cc | 62 ++++++++++++++++------
+ src/std_hooks.lua | 9 +++-
+ test/func-testsuite.lua | 7 +++
+ test/func/automate_get_attributes/__driver__.lua | 2 +-
+ .../func/automate_interface_version/__driver__.lua | 2 +-
+ .../automate_inventory_ignore_dirs/__driver__.lua | 2 +-
+ test/func/automate_put_revision/__driver__.lua | 2 +-
+ .../automate_set_drop_attribute/__driver__.lua | 4 +-
+ .../func/automate_stdio_band_output/__driver__.lua | 10 ++--
+ test/func/clone_weird_branch_names/__driver__.lua | 2 +-
+ test/func/list_databases/__driver__.lua | 6 +--
+ test/func/list_workspaces/__driver__.lua | 8 +--
+ .../log_--no-files_and_--merges/__driver__.lua | 4 +-
+ test/func/manpage/__driver__.lua | 2 +-
+ test/func/netsync_negotiation/__driver__.lua | 8 +--
+ test/func/serve-automate-single-run/__driver__.lua | 2 +-
+ test/func/serve-automate/__driver__.lua | 4 +-
+ test/func/ssh_agent/__driver__.lua | 8 +--
+ .../__driver__.lua | 4 +-
+ test/func/user_commands/extra_rc | 3 +-
+ test/src/testlib.lua | 39 +++++++-------
+ 25 files changed, 161 insertions(+), 89 deletions(-)
+
+diff --git a/extra/mtn-hooks/monotone-cvs-ignore.lua b/extra/mtn-hooks/monotone-cvs-ignore.lua
+index 6a59d12..0e9feb5 100644
+--- a/extra/mtn-hooks/monotone-cvs-ignore.lua
++++ b/extra/mtn-hooks/monotone-cvs-ignore.lua
+@@ -23,7 +23,7 @@ do
+
+ local handle, msg = io.open(dir .. ".cvsignore")
+ if (handle) then
+- for line in handle:lines(dir .. ".cvsignore") do
++ for line in handle:lines() do
+ pat2 = _glob_to_pattern(line) .. "$"
+ if (string.find(name, pat1 .. pat2)) then
+ return true
+diff --git a/src/lua.cc b/src/lua.cc
+index 29f1033..9456c64 100644
+--- a/src/lua.cc
++++ b/src/lua.cc
+@@ -44,7 +44,11 @@ dump_stack(lua_State * st)
+ switch (t) {
+ case LUA_TSTRING: /* strings */
+ out += '`';
++#ifdef lua_strlen
+ out += string(lua_tostring(st, i), lua_strlen(st, i));
++#else
++ out += string(lua_tostring(st, i), lua_rawlen(st, i));
++#endif
+ out += '\'';
+ break;
+
+@@ -95,7 +99,11 @@ void
+ Lua::report_error()
+ {
+ // I(lua_isstring(st, -1));
++#ifdef lua_strlen
+ string err = string(lua_tostring(st, -1), lua_strlen(st, -1));
++#else
++ string err = string(lua_tostring(st, -1), lua_rawlen(st, -1));
++#endif
+ W(i18n_format("%s") % err);
+ L(FL("lua stack: %s") % dump_stack(st));
+ lua_pop(st, 1);
+@@ -107,7 +115,11 @@ Lua::check_stack(int count)
+ {
+ if (!lua_checkstack(st, count))
+ {
++#ifdef LUAI_MAXCSTACK
+ fail((FL("lua stack limit '%d' reached") % LUAI_MAXCSTACK).str());
++#else
++ fail((FL("lua stack limit '%d' reached") % LUAI_MAXSTACK).str());
++#endif
+ return false;
+ }
+ return true;
+@@ -119,17 +131,27 @@ Lua &
+ Lua::get(int idx)
+ {
+ if (failed) return *this;
+- if (!lua_istable (st, idx))
+- {
+- fail("istable() in get");
+- return *this;
+- }
+ if (lua_gettop (st) < 1)
+ {
+ fail("stack top > 0 in get");
+ return *this;
+ }
+- lua_gettable(st, idx);
++ if (idx)
++ {
++ if (!lua_istable (st, idx))
++ {
++ fail("istable() in get");
++ return *this;
++ }
++ lua_gettable(st, idx);
++ }
++ else
++ {
++ string name;
++ extract_str(name);
++ pop();
++ lua_getglobal(st, name.c_str());
++ }
+ return *this;
+ }
+
+@@ -194,7 +216,11 @@ Lua::extract_str_nolog(string & str)
+ fail("isstring() in extract_str");
+ return *this;
+ }
++#ifdef lua_strlen
+ str = string(lua_tostring(st, -1), lua_strlen(st, -1));
++#else
++ str = string(lua_tostring(st, -1), lua_rawlen(st, -1));
++#endif
+ return *this;
+ }
+
+@@ -460,7 +486,7 @@ void add_functions(lua_State * st)
+ {
+ lua_newtable(st);
+ lua_pushvalue(st, -1);
+- lua_setfield(st, LUA_GLOBALSINDEX, table.c_str());
++ lua_setglobal(st, table.c_str());
+ }
+ for (luaext::fmap::const_iterator j = i->second.begin();
+ j != i->second.end(); ++j)
+diff --git a/src/lua.hh b/src/lua.hh
+index ae87329..6f9783a 100644
+--- a/src/lua.hh
++++ b/src/lua.hh
+@@ -37,13 +37,13 @@ Lua
+ void report_error();
+ bool check_stack(int count);
+
+- // getters
+- Lua & get(int idx = LUA_GLOBALSINDEX);
+- Lua & get_fn(int idx = LUA_GLOBALSINDEX);
+- Lua & get_tab(int idx = LUA_GLOBALSINDEX);
+- Lua & get_str(int idx = LUA_GLOBALSINDEX);
+- Lua & get_num(int idx = LUA_GLOBALSINDEX);
+- Lua & get_bool(int idx = LUA_GLOBALSINDEX);
++ // getters (0 is an invalid index in lua, and is used here to represent the global table)
++ Lua & get(int idx = 0);
++ Lua & get_fn(int idx = 0);
++ Lua & get_tab(int idx = 0);
++ Lua & get_str(int idx = 0);
++ Lua & get_num(int idx = 0);
++ Lua & get_bool(int idx = 0);
+
+ // extractors
+ Lua & extract_str_nolog(std::string & str);
+diff --git a/src/luaext_parse_basic_io.cc b/src/luaext_parse_basic_io.cc
+index 84cea98..4d2308a 100644
+--- a/src/luaext_parse_basic_io.cc
++++ b/src/luaext_parse_basic_io.cc
+@@ -23,7 +23,11 @@ LUAEXT(parse_basic_io, )
+ // followed by one or more string or hex values. It returns a table of
+ // lines.
+ vector<pair<string, vector<string> > > res;
++#ifdef lua_strlen
+ const string str(luaL_checkstring(LS, -1), lua_strlen(LS, -1));
++#else
++ const string str(luaL_checkstring(LS, -1), lua_rawlen(LS, -1));
++#endif
+ basic_io::input_source in(str, "monotone_parse_basic_io_for_lua");
+ in.made_from = origin::user;
+ basic_io::tokenizer tok(in);
+diff --git a/src/luaext_platform.cc b/src/luaext_platform.cc
+index 643250c..c89b45a 100644
+--- a/src/luaext_platform.cc
++++ b/src/luaext_platform.cc
+@@ -96,31 +96,58 @@ LUAEXT(spawn_redirected, )
+ return 1;
+ }
+
+-// borrowed from lua/liolib.cc
+-// Note that making C functions that return FILE* in Lua is tricky
++// Making C functions that return FILE* in Lua is tricky. Especially if it
++// actually needs to work with multiple lua versions.
++//
++// The following routines are inspired by lua/liolib.c from both versions.
++// The mtn_lua_Stream struct is closer to the 5.2 variant, but the
++// additional field compared to 5.1 (which only uses FILE*) shouldn't hurt
++// in Lua 5.1.
++//
+ // There is a Lua FAQ entitled:
+ // "Why does my library-created file segfault on :close() but work otherwise?"
++//
++// However, it's advice seems out-dated and applies more to 5.1.
++
++typedef struct mtn_lua_Stream {
++ FILE *f;
++ lua_CFunction closef;
++} mtn_lua_Stream;
++
++#define topfile(LS) ((mtn_lua_Stream *)luaL_checkudata(LS, 1, LUA_FILEHANDLE))
+
+-#define topfile(LS) ((FILE **)luaL_checkudata(LS, 1, LUA_FILEHANDLE))
++static int io_pclose (lua_State *LS) {
++ mtn_lua_Stream *s = topfile(LS);
++
++ // Note that in Lua 5.2, aux_close() already resets s->closef to NULL and for
++ // Lua 5.1, it's not relevant, at all. But we've set it to &io_pclose(), so
++ // contents of s->closef different between Lua versions.
++
++ int ok;
++ if (s->f != NULL)
++ ok = (pclose(s->f) == 0);
++
++ s->f = NULL;
++ s->closef = NULL; // just to be extra sure this won't do any harm
+
+-static int io_fclose (lua_State *LS) {
+- FILE **p = topfile(LS);
+- int ok = (fclose(*p) == 0);
+- *p = NULL;
+ lua_pushboolean(LS, ok);
+ return 1;
+ }
+
+-static FILE **newfile (lua_State *LS) {
+- FILE **pf = (FILE **)lua_newuserdata(LS, sizeof(FILE *));
+- *pf = NULL; /* file handle is currently `closed' */
++static mtn_lua_Stream *newstream (lua_State *LS) {
++ mtn_lua_Stream *s = (mtn_lua_Stream *)lua_newuserdata(LS, sizeof(mtn_lua_Stream));
++ s->f = NULL; /* file handle is currently `closed' */
++ s->closef = NULL;
+ luaL_getmetatable(LS, LUA_FILEHANDLE);
+ lua_setmetatable(LS, -2);
+
+- lua_pushcfunction(LS, io_fclose);
++#ifdef LUA_ENVIRONINDEX
++ // Lua 5.2 removes C function environments
++ lua_pushcfunction(LS, io_pclose);
+ lua_setfield(LS, LUA_ENVIRONINDEX, "__close");
++#endif
+
+- return pf;
++ return s;
+ }
+
+ LUAEXT(spawn_pipe, )
+@@ -136,12 +163,13 @@ LUAEXT(spawn_pipe, )
+ for (i=0; i<n; i++) argv[i] = (char*)luaL_checkstring(LS, i+1);
+ argv[i] = NULL;
+
+- int infd;
+- FILE **inpf = newfile(LS);
+- int outfd;
+- FILE **outpf = newfile(LS);
++ mtn_lua_Stream *ins = newstream(LS);
++ ins->closef = &io_pclose;
++
++ mtn_lua_Stream *outs = newstream(LS);
++ outs->closef = &io_pclose;
+
+- pid = process_spawn_pipe(argv, inpf, outpf);
++ pid = process_spawn_pipe(argv, &ins->f, &outs->f);
+ free(argv);
+
+ lua_pushnumber(LS, pid);
+diff --git a/src/std_hooks.lua b/src/std_hooks.lua
+index bfef561..7099f83 100644
+--- a/src/std_hooks.lua
++++ b/src/std_hooks.lua
+@@ -10,6 +10,13 @@
+ -- this is the standard set of lua hooks for monotone;
+ -- user-provided files can override it or add to it.
+
++-- Since Lua 5.2, unpack and loadstrings are deprecated and are either moved
++-- to table.unpack() or replaced by load(). If lua was compiled without
++-- LUA_COMPAT_UNPACK and/or LUA_COMPAT_LOADSTRING, these two are not
++-- available and we add a similar compatibility layer, ourselves.
++unpack = unpack or table.unpack
++loadstring = loadstring or load
++
+ function temp_file(namehint)
+ local tdir
+ tdir = os.getenv("TMPDIR")
+@@ -1465,7 +1472,7 @@ do
+ return true, warning
+ end
+ function push_hook_functions(functions)
+- local n = table.maxn(hook_functions) + 1
++ local n = #hook_functions + 1
+ return add_hook_functions(functions, n)
+ end
+
+diff --git a/test/func-testsuite.lua b/test/func-testsuite.lua
+index 64a6f26..454cd9c 100755
+--- a/test/func-testsuite.lua
++++ b/test/func-testsuite.lua
+@@ -10,6 +10,13 @@
+ monotone_path = nil
+ no_network_tests = false
+
++-- Since Lua 5.2, unpack and loadstrings are deprecated and are either moved
++-- to table.unpack() or replaced by load(). If lua was compiled without
++-- LUA_COMPAT_UNPACK and/or LUA_COMPAT_LOADSTRING, these two are not
++-- available and we add a similar compatibility layer, ourselves.
++unpack = unpack or table.unpack
++loadstring = loadstring or load
++
+ function safe_mtn(...)
+ if monotone_path == nil then
+ monotone_path = os.getenv("mtn")
+diff --git a/test/func/automate_get_attributes/__driver__.lua b/test/func/automate_get_attributes/__driver__.lua
+index 2e92654..eb91015 100644
+--- a/test/func/automate_get_attributes/__driver__.lua
++++ b/test/func/automate_get_attributes/__driver__.lua
+@@ -28,7 +28,7 @@ check(mtn("automate", "get_attributes", "testfile"), 0, true, true)
+ check(fsize("stderr") == 0)
+ parsed = parse_basic_io(readfile("stdout"))
+ -- make sure the output generated 8 stanzas
+-check(table.getn(parsed) == 8)
++check(#parsed == 8)
+ lastkey = ""
+ checked = {}
+ for _,l in pairs(parsed) do
+diff --git a/test/func/automate_interface_version/__driver__.lua b/test/func/automate_interface_version/__driver__.lua
+index d969d7d..7ff79e9 100644
+--- a/test/func/automate_interface_version/__driver__.lua
++++ b/test/func/automate_interface_version/__driver__.lua
+@@ -7,4 +7,4 @@ rename("stdout", "a_v")
+ -- MinGW's wc produces " 1" as output. Arithmetic comparison works, string comparison doesn't
+ check(numlines("a_v") == 1)
+ -- This is really ^[0-9]+\.[0-9]+$, but m4 is obfuscatory.
+-check(qgrep("^[0-9]+\.[0-9]+$", "a_v"))
++check(qgrep("^[0-9]+\\.[0-9]+$", "a_v"))
+diff --git a/test/func/automate_inventory_ignore_dirs/__driver__.lua b/test/func/automate_inventory_ignore_dirs/__driver__.lua
+index bfb5c25..72a89bb 100644
+--- a/test/func/automate_inventory_ignore_dirs/__driver__.lua
++++ b/test/func/automate_inventory_ignore_dirs/__driver__.lua
+@@ -14,7 +14,7 @@ function sortContentsByLine(input)
+ table.insert(lines, string.sub(input, theStart))
+ table.sort(lines)
+
+- local len = table.getn(lines)
++ local len = #lines
+ local output = lines[1]
+ for i = 2, len do
+ output = output .. delimiter .. lines[i]
+diff --git a/test/func/automate_put_revision/__driver__.lua b/test/func/automate_put_revision/__driver__.lua
+index 2626ec3..32bdacb 100644
+--- a/test/func/automate_put_revision/__driver__.lua
++++ b/test/func/automate_put_revision/__driver__.lua
+@@ -33,5 +33,5 @@ check(mtn("automate", "put_revision", rev), 3, false, false)
+ -- but this should work (tests that we can use put_revision to commit a
+ -- single-parent revision)
+ check(mtn("automate", "put_file", ""), 0, false, false)
+-rev = "format_version \"1\"\n\nnew_manifest [0000000000000000000000000000000000000000]\n\nold_revision [4c2c1d846fa561601254200918fba1fd71e6795d]\n\patch \"foo\"\n from [5bf1fd927dfb8679496a2e6cf00cbe50c1c87145] to [da39a3ee5e6b4b0d3255bfef95601890afd80709]\n"
++rev = "format_version \"1\"\n\nnew_manifest [0000000000000000000000000000000000000000]\n\nold_revision [4c2c1d846fa561601254200918fba1fd71e6795d]\n\npatch \"foo\"\n from [5bf1fd927dfb8679496a2e6cf00cbe50c1c87145] to [da39a3ee5e6b4b0d3255bfef95601890afd80709]\n"
+ check(mtn("automate", "put_revision", rev), 0, false, false)
+diff --git a/test/func/automate_set_drop_attribute/__driver__.lua b/test/func/automate_set_drop_attribute/__driver__.lua
+index 5369cd9..12ff4dc 100644
+--- a/test/func/automate_set_drop_attribute/__driver__.lua
++++ b/test/func/automate_set_drop_attribute/__driver__.lua
+@@ -25,7 +25,7 @@ check(mtn("automate", "set_attribute", "testfile", "foo", "bar"), 0, false, fals
+ check(mtn("automate", "get_attributes", "testfile"), 0, true, false)
+ parsed = parse_basic_io(readfile("stdout"))
+
+-check(table.getn(parsed) == 2)
++check(#parsed == 2)
+ for _,l in pairs(parsed) do
+ if l.name == "attr" then
+ key = l.values[1]
+@@ -44,7 +44,7 @@ check(mtn("automate", "drop_attribute", "testfile", "foo"), 0, true, true)
+ -- check if it has been really dropped
+ check(mtn("automate", "get_attributes", "testfile"), 0, true, false)
+ parsed = parse_basic_io(readfile("stdout"))
+-check(table.getn(parsed) == 0)
++check(#parsed == 0)
+
+ -- check if it escalates properly if there is no such attr to drop
+ check(mtn("automate", "drop_attribute", "testfile", "foo"), 1, false, true)
+diff --git a/test/func/automate_stdio_band_output/__driver__.lua b/test/func/automate_stdio_band_output/__driver__.lua
+index 4262d0e..88c8d63 100755
+--- a/test/func/automate_stdio_band_output/__driver__.lua
++++ b/test/func/automate_stdio_band_output/__driver__.lua
+@@ -4,13 +4,13 @@ mtn_setup()
+
+ -- check informational messages, warnings and errors
+ out = run_stdio("l8:bandtest4:infoe", 0, 0, "p")
+-check(type(out) == "table" and table.maxn(out) == 1)
++check(type(out) == "table" and #out == 1)
+
+ out = run_stdio("l8:bandtest7:warninge", 0, 0, "w")
+-check(type(out) == "table" and table.maxn(out) == 1)
++check(type(out) == "table" and #out == 1)
+
+ out = run_stdio("l8:bandtest5:errore", 2, 0, "e")
+-check(type(out) == "table" and table.maxn(out) == 1)
++check(type(out) == "table" and #out == 1)
+
+ -- check tickers
+ tickers = run_stdio("l8:bandtest6:tickere", 0, 0, "t")
+@@ -38,7 +38,7 @@ end
+ ticker_data = {}
+ for _,tick in ipairs(tickers) do
+ ticks = split(tick, ";")
+- check(table.maxn(ticks) > 0)
++ check(#ticks > 0)
+ for _,mtick in ipairs(ticks) do
+ if string.len(mtick) > 0 then
+ local begin,End,short,ticktype,content =
+@@ -78,6 +78,6 @@ for _,tick in ipairs(tickers) do
+ end
+
+ -- finally check if all tickers are completed
+-check(table.maxn(ticker_data) == 0)
++check(#ticker_data == 0)
+
+
+diff --git a/test/func/clone_weird_branch_names/__driver__.lua b/test/func/clone_weird_branch_names/__driver__.lua
+index 4948a72..a97c6ea 100644
+--- a/test/func/clone_weird_branch_names/__driver__.lua
++++ b/test/func/clone_weird_branch_names/__driver__.lua
+@@ -7,7 +7,7 @@ commit("my-branch[1,2]-1^3")
+
+ copy("test.db", "test-clone.db")
+ -- some of the special chars need to get double-escaped to get "through"
+-testURI="file://" .. test.root .. "/test-clone.db?my-branch\\\[1,2\\\]-1^3"
++testURI="file://" .. test.root .. "/test-clone.db?my-branch\\[1,2\\]-1^3"
+
+ check(nodb_mtn("clone", testURI), 0, false, false)
+ check(exists("my-branch[1,2]-1^3"))
+diff --git a/test/func/list_databases/__driver__.lua b/test/func/list_databases/__driver__.lua
+index e3da0e9..48cd75c 100644
+--- a/test/func/list_databases/__driver__.lua
++++ b/test/func/list_databases/__driver__.lua
+@@ -25,15 +25,15 @@ check(mt("db", "init", "-d", ":bar"), 0, false, false)
+ check(exists("managed_databases/bar.mtn"))
+
+ check(mt("ls", "dbs"), 0, true, false)
+-check(qgrep(":bar.mtn.+in.+list_databases\/managed_databases", "stdout"))
++check(qgrep(":bar.mtn.+in.+list_databases/managed_databases", "stdout"))
+ check(qgrep("\tno known valid workspaces", "stdout"))
+
+ check(mt("setup", "-d", ":bar", "-b", "test.foo.branch", "test_foo"), 0, false, false)
+
+ check(mt("ls", "dbs"), 0, true, false)
+ check(not qgrep("\tno known valid workspaces", "stdout"))
+-check(qgrep("\ttest.foo.branch.+in.+list_databases\/test_foo", "stdout"))
++check(qgrep("\ttest.foo.branch.+in.+list_databases/test_foo", "stdout"))
+
+ check(rename("managed_databases/bar.mtn", "managed_databases/bar.db"))
+ check(mt("ls", "dbs"), 0, true, false)
+-check(qgrep(":bar.db.+in.+list_databases\/managed_databases", "stdout"))
++check(qgrep(":bar.db.+in.+list_databases/managed_databases", "stdout"))
+diff --git a/test/func/list_workspaces/__driver__.lua b/test/func/list_workspaces/__driver__.lua
+index 06dbfef..8895ed4 100644
+--- a/test/func/list_workspaces/__driver__.lua
++++ b/test/func/list_workspaces/__driver__.lua
+@@ -10,17 +10,17 @@ check(samelines("stdout", {"no known valid workspaces"}))
+ check(raw_mtn("setup", "-d", "test.mtn", "-b", "test.branch1", "work1"), 0, false, false)
+
+ check(raw_mtn("ls", "workspaces", "-d", "test.mtn"), 0, true, false)
+-check(qgrep("test.branch1.+in.+list_workspaces\/work1", "stdout"))
++check(qgrep("test.branch1.+in.+list_workspaces/work1", "stdout"))
+
+ check(raw_mtn("setup", "-d", "test.mtn", "-b", "test.branch2", "work2"), 0, false, false)
+ check(rename("work1", "work3"))
+
+ check(raw_mtn("ls", "workspaces", "-d", "test.mtn"), 0, true, false)
+-check(qgrep("test.branch2.+in.+list_workspaces\/work2", "stdout"))
+-check(not qgrep("test.branch1.+in.+list_workspaces\/work1", "stdout"))
++check(qgrep("test.branch2.+in.+list_workspaces/work2", "stdout"))
++check(not qgrep("test.branch1.+in.+list_workspaces/work1", "stdout"))
+
+ check(indir("work3", raw_mtn("register_workspace", "-d", "../test.mtn")), 0, false, false)
+
+ check(raw_mtn("ls", "workspaces", "-d", "test.mtn"), 0, true, false)
+-check(qgrep("test.branch1.+in.+list_workspaces\/work3", "stdout"))
++check(qgrep("test.branch1.+in.+list_workspaces/work3", "stdout"))
+
+diff --git a/test/func/log_--no-files_and_--merges/__driver__.lua b/test/func/log_--no-files_and_--merges/__driver__.lua
+index b27551e..de4d26d 100644
+--- a/test/func/log_--no-files_and_--merges/__driver__.lua
++++ b/test/func/log_--no-files_and_--merges/__driver__.lua
+@@ -29,8 +29,8 @@ R2=base_revision()
+
+ -- check that merge is included by default
+ check(mtn("log"), 0, true, false)
+-check(qgrep("^[\\|\\\\\/ ]+Revision.*"..R2, "stdout"))
++check(qgrep("^[\\|\\\\/ ]+Revision.*"..R2, "stdout"))
+
+ -- and that it is excluded by --no-merges
+ check(mtn("log", "--no-merges"), 0, true, false)
+-check(not qgrep("^[\\|\\\\\/ ]+Revision.*"..R2, "stdout"))
++check(not qgrep("^[\\|\\\\/ ]+Revision.*"..R2, "stdout"))
+diff --git a/test/func/manpage/__driver__.lua b/test/func/manpage/__driver__.lua
+index 775714e..38e5ee7 100644
+--- a/test/func/manpage/__driver__.lua
++++ b/test/func/manpage/__driver__.lua
+@@ -5,7 +5,7 @@ rename("stdout", "manpage")
+
+ -- check for a proper header line
+ check(mtn("version"), 0, true, false)
+-local s,e,version = string.find(readfile("stdout"), "(monotone %d+\.%d+%S*)")
++local s,e,version = string.find(readfile("stdout"), "(monotone %d+%.%d+%S*)")
+ check(qgrep(".TH \"monotone\" 1 \"[0-9]{4}-[0-9]{2}-[0-9]{2}\" \"" .. version .. "\"", "manpage"))
+
+ -- check required sections
+diff --git a/test/func/netsync_negotiation/__driver__.lua b/test/func/netsync_negotiation/__driver__.lua
+index 2efe421..c776f93 100644
+--- a/test/func/netsync_negotiation/__driver__.lua
++++ b/test/func/netsync_negotiation/__driver__.lua
+@@ -87,10 +87,10 @@ function check_same_revs(cmd1, cmd2)
+ check(cmd2, 0, true, false)
+ local data2 = {}
+ for l in io.lines("stdout") do table.insert(data2, l) end
+- L("Command 1 has ", table.getn(data1), " lines.")
+- L("Command 2 has ", table.getn(data2), " lines.")
+- check(table.getn(data1) == table.getn(data2))
+- for i = 1, table.getn(data1) do
++ L("Command 1 has ", #data1, " lines.")
++ L("Command 2 has ", #data2, " lines.")
++ check(#data1 == #data2)
++ for i = 1, #data1 do
+ local hash_len = 40
+ check(data1[i]:sub(1, hash_len) == data2[i]:sub(1, hash_len))
+ end
+diff --git a/test/func/serve-automate-single-run/__driver__.lua b/test/func/serve-automate-single-run/__driver__.lua
+index 87b1ab7..b65b9c1 100644
+--- a/test/func/serve-automate-single-run/__driver__.lua
++++ b/test/func/serve-automate-single-run/__driver__.lua
+@@ -28,7 +28,7 @@ server = netsync.start({"--rcfile=allow-automate.lua"})
+
+ check(mtn2("automate", "remote", "--remote-stdio-host", server.address,
+ "interface_version"), 0, true, false)
+-check(qgrep("^[0-9]{2,}\.[0-9]+$", "stdout"))
++check(qgrep("^[0-9]{2,}\\.[0-9]+$", "stdout"))
+
+ check(mtn2("automate", "remote", "--remote-stdio-host", server.address,
+ "leaves"), 0, true, false)
+diff --git a/test/func/serve-automate/__driver__.lua b/test/func/serve-automate/__driver__.lua
+index 32b2eaf..9e993dc 100644
+--- a/test/func/serve-automate/__driver__.lua
++++ b/test/func/serve-automate/__driver__.lua
+@@ -14,7 +14,7 @@ server = netsync.start({"--rcfile=deny-automate.lua"})
+
+ local errors = run_remote_stdio(server, "l17:interface_versione", 1, 0, "e")
+ check(
+- table.maxn(errors) == 1 and
++ #errors == 1 and
+ errors[1] == "misuse: Sorry, you aren't allowed to do that."
+ )
+
+@@ -45,7 +45,7 @@ check(
+
+ local errors = run_remote_stdio(server, "l5:stdioe", 1, 0, "e")
+ check(
+- table.maxn(errors) == 1 and
++ #errors == 1 and
+ errors[1] == "error: sorry, that can't be run remotely or over stdio"
+ )
+
+diff --git a/test/func/ssh_agent/__driver__.lua b/test/func/ssh_agent/__driver__.lua
+index d927360..a36ce90 100644
+--- a/test/func/ssh_agent/__driver__.lua
++++ b/test/func/ssh_agent/__driver__.lua
+@@ -81,7 +81,7 @@ end
+
+ check({"ssh-agent"}, 0, true, false)
+ for line in io.lines("stdout") do
+- for k, v in string.gmatch(line, "([%w_]+)=([%w/\.-]+)") do
++ for k, v in string.gmatch(line, "([%w_]+)=([%w/%.-]+)") do
+ set_env(k, v)
+ end
+ end
+@@ -91,7 +91,7 @@ check(mtn("ssh_agent_add"), 0, false, false)
+ check({"ssh-add", "-l"}, 0, true, false)
+ ok = false
+ for line in io.lines("stdout") do
+- for k in string.gmatch(line, "tester at test\.net") do
++ for k in string.gmatch(line, "tester at test%.net") do
+ ok = true
+ end
+ end
+@@ -288,7 +288,7 @@ check(mtn("ssh_agent_add", "--key", "test2 at tester.net"), 0, false, false)
+ check({"ssh-add", "-l"}, 0, true, false)
+ ok = false
+ for line in io.lines("stdout") do
+- for k in string.gmatch(line, "test2 at tester\.net") do
++ for k in string.gmatch(line, "test2 at tester%.net") do
+ ok = true
+ end
+ end
+@@ -338,7 +338,7 @@ check(mtn("ssh_agent_add", "--key", "test_pass at tester.net"), 0, false, false, "p
+ check({"ssh-add", "-l"}, 0, true, false)
+ ok = false
+ for line in io.lines("stdout") do
+- for k in string.gmatch(line, "test_pass at tester\.net") do
++ for k in string.gmatch(line, "test_pass at tester%.net") do
+ ok = true
+ end
+ end
+diff --git a/test/func/two_parent_workspace_inodeprints/__driver__.lua b/test/func/two_parent_workspace_inodeprints/__driver__.lua
+index bd6c558..66d5150 100644
+--- a/test/func/two_parent_workspace_inodeprints/__driver__.lua
++++ b/test/func/two_parent_workspace_inodeprints/__driver__.lua
+@@ -19,13 +19,13 @@ check(mtn("merge_into_workspace", other), 0, false, false)
+
+ -- check that we've got the expected initial status
+ check(mtn("status"), 0, true, false)
+-check(qgrep("patched[ ]\+foo", "stdout"))
++check(qgrep("patched[ ]+foo", "stdout"))
+
+ -- enable inodeprints
+ writefile("_MTN/inodeprints")
+
+ check(mtn("status"), 0, true, false)
+-check(qgrep("patched[ ]\+foo", "stdout"))
++check(qgrep("patched[ ]+foo", "stdout"))
+
+ sleep(5)
+
+diff --git a/test/func/user_commands/extra_rc b/test/func/user_commands/extra_rc
+index 2ec5f9f..aad3764 100644
+--- a/test/func/user_commands/extra_rc
++++ b/test/func/user_commands/extra_rc
+@@ -5,7 +5,8 @@ function check_head(...)
+ io.stderr:write("automate call failed\n")
+ return
+ end
+- arghead = unpack(arg)
++ local arg = {...}
++ arghead = arg[1]
+ heads = heads:gsub("^%s*(.-)%s*$", "%1") -- trim leading and trailing whitespace
+ if (heads == arghead) then
+ io.write("heads are equal\n")
+diff --git a/test/src/testlib.lua b/test/src/testlib.lua
+index 6d21a93..19eb278 100644
+--- a/test/src/testlib.lua
++++ b/test/src/testlib.lua
+@@ -30,6 +30,13 @@ files = {stdout = nil, stdin = nil, stderr = nil}
+ -- for convenience, this is the first word of what get_ostype() returns.
+ ostype = string.sub(get_ostype(), 1, string.find(get_ostype(), " ")-1)
+
++-- Since Lua 5.2, unpack and loadstrings are deprecated and are either moved
++-- to table.unpack() or replaced by load(). If lua was compiled without
++-- LUA_COMPAT_UNPACK and/or LUA_COMPAT_LOADSTRING, these two are not
++-- available and we add a similar compatibility layer, ourselves.
++unpack = unpack or table.unpack
++loadstring = loadstring or load
++
+ -- table of per-test values
+ test = {}
+ -- misc per-test values
+@@ -310,17 +317,11 @@ end
+ -- to want to include from the dir for the current test,
+ -- since in that case it could just go in the driver file.
+ function include(name)
+- local func, e = loadfile(testdir.."/"..name)
+- if func == nil then err(e, 2) end
+- setfenv(func, getfenv(2))
+- func()
++ dofile(testdir.."/"..name)
+ end
+
+ function includecommon(name)
+- local func, e = loadfile(srcdir.."/common/"..name)
+- if func == nil then err(e, 2) end
+- setfenv(func, getfenv(2))
+- func()
++ dofile(srcdir.."/common/"..name)
+ end
+
+ function trim(str)
+@@ -479,12 +480,11 @@ end
+ function samelines(f, t)
+ local fl = {}
+ for l in io.lines(f) do table.insert(fl, l) end
+- if not (table.getn(fl) == table.getn(t)) then
+- L(locheader(), string.format("file has %s lines; table has %s\n",
+- table.getn(fl), table.getn(t)))
++ if not (#fl == #t) then
++ L(locheader(), string.format("file has %s lines; table has %s\n", #fl, #t))
+ return false
+ end
+- for i=1,table.getn(t) do
++ for i=1,#t do
+ if fl[i] ~= t[i] then
+ if fl[i] then
+ L(locheader(), string.format("file[%d] = '%s'; table[%d] = '%s'\n",
+@@ -502,12 +502,11 @@ end
+ function greplines(f, t)
+ local fl = {}
+ for l in io.lines(f) do table.insert(fl, l) end
+- if not (table.getn(fl) == table.getn(t)) then
+- L(locheader(), string.format("file has %s lines; table has %s\n",
+- table.getn(fl), table.getn(t)))
++ if not (#fl == #t) then
++ L(locheader(), string.format("file has %s lines; table has %s\n", #fl, #t))
+ return false
+ end
+- for i=1,table.getn(t) do
++ for i=1,#t do
+ if not regex.search(t[i], fl[i]) then
+ L(locheader(), string.format("file[i] = '%s'; table[i] = '%s'\n",
+ fl[i], t[i]))
+@@ -577,7 +576,7 @@ function tail(...)
+ local mylines = {}
+ for l in io.lines(file) do
+ table.insert(mylines, l)
+- if table.getn(mylines) > num then
++ if #mylines > num then
+ table.remove(mylines, 1)
+ end
+ end
+@@ -932,8 +931,8 @@ function run_tests(debugging, list_only, run_dir, logname, args, progress)
+ if _1 then
+ l = l + 0
+ r = r + 0
+- if l < 1 then l = table.getn(tests) + l + 1 end
+- if r < 1 then r = table.getn(tests) + r + 1 end
++ if l < 1 then l = #tests + l + 1 end
++ if r < 1 then r = #tests + r + 1 end
+ if l > r then l,r = r,l end
+ for j = l,r do
+ torun[j] = tests[j]
+@@ -941,7 +940,7 @@ function run_tests(debugging, list_only, run_dir, logname, args, progress)
+ run_all = false
+ elseif string.find(a, "^-?%d+$") then
+ r = a + 0
+- if r < 1 then r = table.getn(tests) + r + 1 end
++ if r < 1 then r = #tests + r + 1 end
+ torun[r] = tests[r]
+ run_all = false
+ else
+--
+tg: (1150daa..) lua-5.2 (depends on: master)
diff --git a/monotone.spec b/monotone.spec
index 2696f24..57e244a 100644
--- a/monotone.spec
+++ b/monotone.spec
@@ -1,6 +1,6 @@
Name: monotone
Version: 1.0
-Release: 14%{?dist}
+Release: 15%{?dist}
Summary: A free, distributed version control system
Group: Development/Tools
License: GPLv2+
@@ -23,6 +23,13 @@ Patch3: monotone-1.0-pcre.patch
Patch4: monotone-1.0-fix-bash_completion-test.patch
# See rhbz#919827
Patch5: monotone-1.0-fix-diff_patch_drop-test.patch
+# Fix FTBFS for Botan 1.10.X
+# https://code.monotone.ca/p/monotone/issues/182/
+Patch6: monotone-1.0-botan-1.10.patch
+# Fix FTBFS for Lua 5.2
+Patch7: monotone-1.0-lua-5.2.patch
+# Fix texinfo errors with texinfo >= 5.0
+Patch8: monotone-1.0-fix-texinfo.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: zlib-devel
BuildRequires: boost-devel >= 1.33.1
@@ -85,6 +92,9 @@ and then pass commands to it.
%patch3 -p1
%patch4 -p1
%patch5 -p1
+%patch6 -p1
+%patch7 -p1
+%patch8 -p1
# fix FTBFS rhbz#914191
sed -e "s|shared_dynamic_cast|dynamic_pointer_cast|g" \
@@ -98,12 +108,14 @@ make %{?_smp_mflags}
%check
+export LC_MESSAGES=en_US
export DISABLE_NETWORK_TESTS=1
make %{?_smp_mflags} check || { head -n-0 test/work/*.log; false; }
%install
rm -rf %{buildroot}
+export LC_MESSAGES=en_US
make install DESTDIR=%{buildroot}
rm -f %{buildroot}%{_infodir}/dir
mv %{buildroot}%{_datadir}/doc/%{name} _doc
@@ -234,6 +246,10 @@ fi
%changelog
+* Tue Oct 8 2013 Thomas Moschny <thomas.moschny at gmx.de> - 1.0-15
+- Add patches for building with Botan 1.10, Lua 5.2,
+ and Texinfo >= 5.0.
+
* Sat Aug 03 2013 Fedora Release Engineering <rel-eng at lists.fedoraproject.org> - 1.0-14
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
More information about the scm-commits
mailing list