This commit is contained in:
2022-02-03 23:45:47 -08:00
parent 42c2062cc4
commit 184ece190c
1438 changed files with 404064 additions and 0 deletions
+56
View File
@@ -0,0 +1,56 @@
Wallet Tools
---------------------
### [BitRPC](/contrib/bitrpc) ###
Allows for sending of all standard Bitcoin commands via RPC rather than as command line args.
### [SpendFrom](/contrib/spendfrom) ###
Use the raw transactions API to send coins received on a particular
address (or addresses).
Repository Tools
---------------------
### [Developer tools](/contrib/devtools) ###
Specific tools for developers working on this repository.
Contains the script `github-merge.sh` for merging github pull requests securely and signing them using GPG.
### [Linearize](/contrib/linearize) ###
Construct a linear, no-fork, best version of the blockchain.
### [Qos](/contrib/qos) ###
A Linux bash script that will set up traffic control (tc) to limit the outgoing bandwidth for connections to the Bitcoin network. This means one can have an always-on bitcoind instance running, and another local bitcoind/bitcoin-qt instance which connects to this node and receives blocks from it.
### [Seeds](/contrib/seeds) ###
Utility to generate the pnSeed[] array that is compiled into the client.
Build Tools and Keys
---------------------
### [Debian](/contrib/debian) ###
Contains files used to package bitcoind/bitcoin-qt
for Debian-based Linux systems. If you compile bitcoind/bitcoin-qt yourself, there are some useful files here.
### [Gitian-descriptors](/contrib/gitian-descriptors) ###
Gavin's notes on getting gitian builds up and running using KVM.
### [Gitian-downloader](/contrib/gitian-downloader)
Various PGP files of core developers.
### [MacDeploy](/contrib/macdeploy) ###
Scripts and notes for Mac builds.
Test and Verify Tools
---------------------
### [TestGen](/contrib/testgen) ###
Utilities to generate test vectors for the data-driven Bitcoin tests.
### [Test Patches](/contrib/test-patches) ###
These patches are applied when the automated pull-tester
tests each pull and when master is tested using jenkins.
### [Verify SF Binaries](/contrib/verifysfbinaries) ###
This script attempts to download and verify the signature file SHA256SUMS.asc from SourceForge.
+154
View File
@@ -0,0 +1,154 @@
# bash programmable completion for agrarian-cli(1)
# Copyright (c) 2012-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# call $agrarian-cli for RPC
_agrarian_rpc() {
# determine already specified args necessary for RPC
local rpcargs=()
for i in ${COMP_LINE}; do
case "$i" in
-conf=*|-datadir=*|-regtest|-rpc*|-testnet)
rpcargs=( "${rpcargs[@]}" "$i" )
;;
esac
done
$agrarian_cli "${rpcargs[@]}" "$@"
}
# Add wallet accounts to COMPREPLY
_agrarian_accounts() {
local accounts
accounts=$(_agrarian_rpc listaccounts | awk -F '"' '{ print $2 }')
COMPREPLY=( "${COMPREPLY[@]}" $( compgen -W "$accounts" -- "$cur" ) )
}
_agrarian_cli() {
local cur prev words=() cword
local agrarian_cli
# save and use original argument to invoke agrarian-cli for -help, help and RPC
# as agrarian-cli might not be in $PATH
agrarian_cli="$1"
COMPREPLY=()
_get_comp_words_by_ref -n = cur prev words cword
if ((cword > 5)); then
case ${words[cword-5]} in
sendtoaddress)
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
return 0
;;
esac
fi
if ((cword > 4)); then
case ${words[cword-4]} in
importaddress|listtransactions|setban)
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
return 0
;;
signrawtransaction)
COMPREPLY=( $( compgen -W "ALL NONE SINGLE ALL|ANYONECANPAY NONE|ANYONECANPAY SINGLE|ANYONECANPAY" -- "$cur" ) )
return 0
;;
esac
fi
if ((cword > 3)); then
case ${words[cword-3]} in
addmultisigaddress)
_agrarian_accounts
return 0
;;
getbalance|gettxout|importaddress|importpubkey|importprivkey|listreceivedbyaccount|listreceivedbyaddress|listsinceblock)
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
return 0
;;
esac
fi
if ((cword > 2)); then
case ${words[cword-2]} in
addnode)
COMPREPLY=( $( compgen -W "add remove onetry" -- "$cur" ) )
return 0
;;
setban)
COMPREPLY=( $( compgen -W "add remove" -- "$cur" ) )
return 0
;;
fundrawtransaction|getblock|getblockheader|getmempoolancestors|getmempooldescendants|getrawtransaction|gettransaction|listaccounts|listreceivedbyaccount|listreceivedbyaddress|sendrawtransaction)
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
return 0
;;
move|setaccount)
_agrarian_accounts
return 0
;;
esac
fi
case "$prev" in
backupwallet|dumpwallet|importwallet)
_filedir
return 0
;;
getaddednodeinfo|getrawmempool|lockunspent|setgenerate)
COMPREPLY=( $( compgen -W "true false" -- "$cur" ) )
return 0
;;
getaccountaddress|getaddressesbyaccount|getbalance|getnewaddress|getreceivedbyaccount|listtransactions|move|sendfrom|sendmany)
_agrarian_accounts
return 0
;;
esac
case "$cur" in
-conf=*)
cur="${cur#*=}"
_filedir
return 0
;;
-datadir=*)
cur="${cur#*=}"
_filedir -d
return 0
;;
-*=*) # prevent nonsense completions
return 0
;;
*)
local helpopts commands
# only parse -help if senseful
if [[ -z "$cur" || "$cur" =~ ^- ]]; then
helpopts=$($agrarian_cli -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' )
fi
# only parse help if senseful
if [[ -z "$cur" || "$cur" =~ ^[a-z] ]]; then
commands=$(_agrarian_rpc help 2>/dev/null | awk '$1 ~ /^[a-z]/ { print $1; }')
fi
COMPREPLY=( $( compgen -W "$helpopts $commands" -- "$cur" ) )
# Prevent space if an argument is desired
if [[ $COMPREPLY == *= ]]; then
compopt -o nospace
fi
return 0
;;
esac
} &&
complete -F _agrarian_cli agrarian-cli
# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=sh
+660
View File
@@ -0,0 +1,660 @@
######################################################################
# Automatically generated by qmake (2.01a) ?? ??? 23 17:50:54 2015
######################################################################
DEFINES += ENABLE_WALLET
TEMPLATE = app
TARGET =
DEPENDPATH += . \
src \
src/compat \
src/config \
src/crypto \
src/json \
src/obj \
src/primitives \
src/qt \
src/script \
src/test \
src/univalue \
src/leveldb/db \
src/leveldb/issues \
src/leveldb/port \
src/leveldb/table \
src/leveldb/util \
src/qt/forms \
src/qt/locale \
src/qt/test \
src/secp256k1/include \
src/secp256k1/src \
src/test/data \
src/leveldb/doc/bench \
src/leveldb/helpers/memenv \
src/leveldb/include/leveldb \
src/leveldb/port/win \
src/secp256k1/src/java
INCLUDEPATH += . \
src \
src/config \
src/leveldb/port/win \
src/crypto \
src/primitives \
src/script \
src/obj \
src/univalue \
src/json \
src/qt \
src/qt/forms \
src/compat \
src/secp256k1/include \
src/leveldb/helpers/memenv \
src/test/data \
src/test \
src/qt/test \
src/secp256k1/src \
src/secp256k1/src/java
# Input
HEADERS += src/activemasternode.h \
src/addrman.h \
src/alert.h \
src/allocators.h \
src/amount.h \
src/base58.h \
src/bloom.h \
src/chain.h \
src/chainparams.h \
src/chainparamsbase.h \
src/chainparamsseeds.h \
src/checkpoints.h \
src/checkqueue.h \
src/clientversion.h \
src/coincontrol.h \
src/coins.h \
src/compat.h \
src/compressor.h \
src/core_io.h \
src/crypter.h \
src/obfuscation-relay.h \
src/obfuscation.h \
src/agrarian-config.h \
src/db.h \
src/eccryptoverify.h \
src/ecwrapper.h \
src/hash.h \
src/init.h \
src/swifttx.h \
src/keepass.h \
src/key.h \
src/keystore.h \
src/leveldbwrapper.h \
src/limitedmap.h \
src/main.h \
src/masternode-budget.h \
src/masternode-payments.h \
src/masternode-sync.h \
src/masternode.h \
src/masternodeconfig.h \
src/masternodeman.h \
src/merkleblock.h \
src/miner.h \
src/mruset.h \
src/net.h \
src/netbase.h \
src/noui.h \
src/pow.h \
src/protocol.h \
src/pubkey.h \
src/random.h \
src/rpcclient.h \
src/rpcprotocol.h \
src/rpcserver.h \
src/serialize.h \
src/spork.h \
src/streams.h \
src/sync.h \
src/threadsafety.h \
src/timedata.h \
src/tinyformat.h \
src/txdb.h \
src/txmempool.h \
src/ui_interface.h \
src/uint256.h \
src/undo.h \
src/util.h \
src/utilmoneystr.h \
src/utilstrencodings.h \
src/utiltime.h \
src/version.h \
src/wallet.h \
src/wallet_ismine.h \
src/walletdb.h \
src/compat/sanity.h \
src/config/agrarian-config.h \
src/crypto/common.h \
src/crypto/hmac_sha256.h \
src/crypto/hmac_sha512.h \
src/crypto/rfc6979_hmac_sha256.h \
src/crypto/ripemd160.h \
src/crypto/sha1.h \
src/crypto/sha256.h \
src/crypto/sha512.h \
src/crypto/sph_blake.h \
src/crypto/sph_bmw.h \
src/crypto/sph_cubehash.h \
src/crypto/sph_echo.h \
src/crypto/sph_groestl.h \
src/crypto/sph_jh.h \
src/crypto/sph_keccak.h \
src/crypto/sph_luffa.h \
src/crypto/sph_shavite.h \
src/crypto/sph_simd.h \
src/crypto/sph_skein.h \
src/crypto/sph_types.h \
src/json/json_spirit.h \
src/json/json_spirit_error_position.h \
src/json/json_spirit_reader.h \
src/json/json_spirit_reader_template.h \
src/json/json_spirit_stream_reader.h \
src/json/json_spirit_utils.h \
src/json/json_spirit_value.h \
src/json/json_spirit_writer.h \
src/json/json_spirit_writer_template.h \
src/obj/build.h \
src/primitives/block.h \
src/primitives/transaction.h \
src/qt/addressbookpage.h \
src/qt/addresstablemodel.h \
src/qt/askpassphrasedialog.h \
src/qt/bitcoinaddressvalidator.h \
src/qt/bitcoinamountfield.h \
src/qt/bitcoingui.h \
src/qt/bitcoinunits.h \
src/qt/clientmodel.h \
src/qt/coincontroldialog.h \
src/qt/coincontroltreewidget.h \
src/qt/csvmodelwriter.h \
src/qt/obfuscationconfig.h \
src/qt/editaddressdialog.h \
src/qt/guiconstants.h \
src/qt/guiutil.h \
src/qt/intro.h \
src/qt/macdockiconhandler.h \
src/qt/macnotificationhandler.h \
src/qt/networkstyle.h \
src/qt/notificator.h \
src/qt/openuridialog.h \
src/qt/optionsdialog.h \
src/qt/optionsmodel.h \
src/qt/overviewpage.h \
src/qt/paymentrequest.pb.h \
src/qt/paymentrequestplus.h \
src/qt/paymentserver.h \
src/qt/peertablemodel.h \
src/qt/qvalidatedlineedit.h \
src/qt/qvaluecombobox.h \
src/qt/receivecoinsdialog.h \
src/qt/receiverequestdialog.h \
src/qt/recentrequeststablemodel.h \
src/qt/rpcconsole.h \
src/qt/sendcoinsdialog.h \
src/qt/sendcoinsentry.h \
src/qt/signverifymessagedialog.h \
src/qt/splashscreen.h \
src/qt/trafficgraphwidget.h \
src/qt/transactiondesc.h \
src/qt/transactiondescdialog.h \
src/qt/transactionfilterproxy.h \
src/qt/transactionrecord.h \
src/qt/transactiontablemodel.h \
src/qt/transactionview.h \
src/qt/utilitydialog.h \
src/qt/walletframe.h \
src/qt/walletmodel.h \
src/qt/walletmodeltransaction.h \
src/qt/walletview.h \
src/qt/winshutdownmonitor.h \
src/script/bitcoinconsensus.h \
src/script/interpreter.h \
src/script/script.h \
src/script/script_error.h \
src/script/sigcache.h \
src/script/sign.h \
src/script/standard.h \
src/univalue/univalue.h \
src/univalue/univalue_escapes.h \
src/leveldb/db/builder.h \
src/leveldb/db/db_impl.h \
src/leveldb/db/db_iter.h \
src/leveldb/db/dbformat.h \
src/leveldb/db/filename.h \
src/leveldb/db/log_format.h \
src/leveldb/db/log_reader.h \
src/leveldb/db/log_writer.h \
src/leveldb/db/memtable.h \
src/leveldb/db/skiplist.h \
src/leveldb/db/snapshot.h \
src/leveldb/db/table_cache.h \
src/leveldb/db/version_edit.h \
src/leveldb/db/version_set.h \
src/leveldb/db/write_batch_internal.h \
src/leveldb/port/atomic_pointer.h \
src/leveldb/port/port.h \
src/leveldb/port/port_example.h \
src/leveldb/port/port_posix.h \
src/leveldb/port/port_win.h \
src/leveldb/port/thread_annotations.h \
src/leveldb/table/block.h \
src/leveldb/table/block_builder.h \
src/leveldb/table/filter_block.h \
src/leveldb/table/format.h \
src/leveldb/table/iterator_wrapper.h \
src/leveldb/table/merger.h \
src/leveldb/table/two_level_iterator.h \
src/leveldb/util/arena.h \
src/leveldb/util/coding.h \
src/leveldb/util/crc32c.h \
src/leveldb/util/hash.h \
src/leveldb/util/histogram.h \
src/leveldb/util/logging.h \
src/leveldb/util/mutexlock.h \
src/leveldb/util/posix_logger.h \
src/leveldb/util/random.h \
src/leveldb/util/testharness.h \
src/leveldb/util/testutil.h \
src/qt/forms/ui_aboutdialog.h \
src/qt/test/paymentrequestdata.h \
src/qt/test/paymentservertests.h \
src/qt/test/uritests.h \
src/secp256k1/include/secp256k1.h \
src/secp256k1/src/ecdsa.h \
src/secp256k1/src/ecdsa_impl.h \
src/secp256k1/src/eckey.h \
src/secp256k1/src/eckey_impl.h \
src/secp256k1/src/ecmult.h \
src/secp256k1/src/ecmult_gen.h \
src/secp256k1/src/ecmult_gen_impl.h \
src/secp256k1/src/ecmult_impl.h \
src/secp256k1/src/field.h \
src/secp256k1/src/field_10x26.h \
src/secp256k1/src/field_10x26_impl.h \
src/secp256k1/src/field_5x52.h \
src/secp256k1/src/field_5x52_asm_impl.h \
src/secp256k1/src/field_5x52_impl.h \
src/secp256k1/src/field_5x52_int128_impl.h \
src/secp256k1/src/field_gmp.h \
src/secp256k1/src/field_gmp_impl.h \
src/secp256k1/src/field_impl.h \
src/secp256k1/src/group.h \
src/secp256k1/src/group_impl.h \
src/secp256k1/src/libsecp256k1-config.h \
src/secp256k1/src/num.h \
src/secp256k1/src/num_gmp.h \
src/secp256k1/src/num_gmp_impl.h \
src/secp256k1/src/num_impl.h \
src/secp256k1/src/scalar.h \
src/secp256k1/src/scalar_4x64.h \
src/secp256k1/src/scalar_4x64_impl.h \
src/secp256k1/src/scalar_8x32.h \
src/secp256k1/src/scalar_8x32_impl.h \
src/secp256k1/src/scalar_impl.h \
src/secp256k1/src/testrand.h \
src/secp256k1/src/testrand_impl.h \
src/secp256k1/src/util.h \
src/test/data/alertTests.raw.h \
src/test/data/base58_encode_decode.json.h \
src/test/data/base58_keys_invalid.json.h \
src/test/data/base58_keys_valid.json.h \
src/test/data/script_invalid.json.h \
src/test/data/script_valid.json.h \
src/test/data/sig_canonical.json.h \
src/test/data/sig_noncanonical.json.h \
src/test/data/sighash.json.h \
src/test/data/tx_invalid.json.h \
src/test/data/tx_valid.json.h \
src/leveldb/helpers/memenv/memenv.h \
src/leveldb/include/leveldb/c.h \
src/leveldb/include/leveldb/cache.h \
src/leveldb/include/leveldb/comparator.h \
src/leveldb/include/leveldb/db.h \
src/leveldb/include/leveldb/dumpfile.h \
src/leveldb/include/leveldb/env.h \
src/leveldb/include/leveldb/filter_policy.h \
src/leveldb/include/leveldb/iterator.h \
src/leveldb/include/leveldb/options.h \
src/leveldb/include/leveldb/slice.h \
src/leveldb/include/leveldb/status.h \
src/leveldb/include/leveldb/table.h \
src/leveldb/include/leveldb/table_builder.h \
src/leveldb/include/leveldb/write_batch.h \
src/leveldb/port/win/stdint.h \
src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.h \
src/crypto/aes_helper.c \
src/qt/bitcoinamountfield.moc \
src/qt/agrarian.moc \
src/qt/intro.moc \
src/qt/overviewpage.moc \
src/qt/rpcconsole.moc \
src/secp256k1/src/secp256k1.c
FORMS += src/qt/forms/addressbookpage.ui \
src/qt/forms/askpassphrasedialog.ui \
src/qt/forms/coincontroldialog.ui \
src/qt/forms/obfuscationconfig.ui \
src/qt/forms/editaddressdialog.ui \
src/qt/forms/helpmessagedialog.ui \
src/qt/forms/intro.ui \
src/qt/forms/openuridialog.ui \
src/qt/forms/optionsdialog.ui \
src/qt/forms/overviewpage.ui \
src/qt/forms/receivecoinsdialog.ui \
src/qt/forms/receiverequestdialog.ui \
src/qt/forms/rpcconsole.ui \
src/qt/forms/sendcoinsdialog.ui \
src/qt/forms/sendcoinsentry.ui \
src/qt/forms/signverifymessagedialog.ui \
src/qt/forms/transactiondescdialog.ui
SOURCES += src/activemasternode.cpp \
src/addrman.cpp \
src/alert.cpp \
src/allocators.cpp \
src/amount.cpp \
src/base58.cpp \
src/bloom.cpp \
src/chain.cpp \
src/chainparams.cpp \
src/chainparamsbase.cpp \
src/checkpoints.cpp \
src/clientversion.cpp \
src/coins.cpp \
src/compressor.cpp \
src/core_read.cpp \
src/core_write.cpp \
src/crypter.cpp \
src/obfuscation-relay.cpp \
src/obfuscation.cpp \
src/agrarian-cli.cpp \
src/agrarian-tx.cpp \
src/agrarian.cpp \
src/db.cpp \
src/eccryptoverify.cpp \
src/ecwrapper.cpp \
src/editaddressdialog.cpp \
src/hash.cpp \
src/init.cpp \
src/swifttx.cpp \
src/keepass.cpp \
src/key.cpp \
src/keystore.cpp \
src/leveldbwrapper.cpp \
src/main.cpp \
src/masternode-budget.cpp \
src/masternode-payments.cpp \
src/masternode-sync.cpp \
src/masternode.cpp \
src/masternodeconfig.cpp \
src/masternodeman.cpp \
src/merkleblock.cpp \
src/miner.cpp \
src/net.cpp \
src/netbase.cpp \
src/noui.cpp \
src/pow.cpp \
src/protocol.cpp \
src/pubkey.cpp \
src/random.cpp \
src/rest.cpp \
src/rpcblockchain.cpp \
src/rpcclient.cpp \
src/rpcdump.cpp \
src/rpcmasternode-budget.cpp \
src/rpcmasternode.cpp \
src/rpcmining.cpp \
src/rpcmisc.cpp \
src/rpcnet.cpp \
src/rpcprotocol.cpp \
src/rpcrawtransaction.cpp \
src/rpcserver.cpp \
src/rpcwallet.cpp \
src/spork.cpp \
src/sync.cpp \
src/timedata.cpp \
src/txdb.cpp \
src/txmempool.cpp \
src/uint256.cpp \
src/util.cpp \
src/utilmoneystr.cpp \
src/utilstrencodings.cpp \
src/utiltime.cpp \
src/wallet.cpp \
src/wallet_ismine.cpp \
src/walletdb.cpp \
src/compat/glibc_compat.cpp \
src/compat/glibc_sanity.cpp \
src/compat/glibcxx_compat.cpp \
src/compat/glibcxx_sanity.cpp \
src/compat/strnlen.cpp \
src/crypto/aes_helper.c \
src/crypto/blake.c \
src/crypto/bmw.c \
src/crypto/cubehash.c \
src/crypto/echo.c \
src/crypto/groestl.c \
src/crypto/hmac_sha256.cpp \
src/crypto/hmac_sha512.cpp \
src/crypto/jh.c \
src/crypto/keccak.c \
src/crypto/luffa.c \
src/crypto/rfc6979_hmac_sha256.cpp \
src/crypto/ripemd160.cpp \
src/crypto/sha1.cpp \
src/crypto/sha256.cpp \
src/crypto/sha512.cpp \
src/crypto/shavite.c \
src/crypto/simd.c \
src/crypto/skein.c \
src/json/json_spirit_reader.cpp \
src/json/json_spirit_value.cpp \
src/json/json_spirit_writer.cpp \
src/primitives/block.cpp \
src/primitives/transaction.cpp \
src/qt/addressbookpage.cpp \
src/qt/addresstablemodel.cpp \
src/qt/askpassphrasedialog.cpp \
src/qt/bitcoinaddressvalidator.cpp \
src/qt/bitcoinamountfield.cpp \
src/qt/bitcoingui.cpp \
src/qt/bitcoinunits.cpp \
src/qt/clientmodel.cpp \
src/qt/coincontroldialog.cpp \
src/qt/coincontroltreewidget.cpp \
src/qt/csvmodelwriter.cpp \
src/qt/obfuscationconfig.cpp \
src/qt/agrarian.cpp \
src/qt/agrarianstrings.cpp \
src/qt/editaddressdialog.cpp \
src/qt/guiutil.cpp \
src/qt/intro.cpp \
src/qt/networkstyle.cpp \
src/qt/notificator.cpp \
src/qt/openuridialog.cpp \
src/qt/optionsdialog.cpp \
src/qt/optionsmodel.cpp \
src/qt/overviewpage.cpp \
src/qt/paymentrequest.pb.cc \
src/qt/paymentrequestplus.cpp \
src/qt/paymentserver.cpp \
src/qt/peertablemodel.cpp \
src/qt/qvalidatedlineedit.cpp \
src/qt/qvaluecombobox.cpp \
src/qt/receivecoinsdialog.cpp \
src/qt/receiverequestdialog.cpp \
src/qt/recentrequeststablemodel.cpp \
src/qt/rpcconsole.cpp \
src/qt/sendcoinsdialog.cpp \
src/qt/sendcoinsentry.cpp \
src/qt/signverifymessagedialog.cpp \
src/qt/splashscreen.cpp \
src/qt/trafficgraphwidget.cpp \
src/qt/transactiondesc.cpp \
src/qt/transactiondescdialog.cpp \
src/qt/transactionfilterproxy.cpp \
src/qt/transactionrecord.cpp \
src/qt/transactiontablemodel.cpp \
src/qt/transactionview.cpp \
src/qt/utilitydialog.cpp \
src/qt/walletframe.cpp \
src/qt/walletmodel.cpp \
src/qt/walletmodeltransaction.cpp \
src/qt/walletview.cpp \
src/qt/winshutdownmonitor.cpp \
src/script/bitcoinconsensus.cpp \
src/script/interpreter.cpp \
src/script/script.cpp \
src/script/script_error.cpp \
src/script/sigcache.cpp \
src/script/sign.cpp \
src/script/standard.cpp \
src/test/accounting_tests.cpp \
src/test/alert_tests.cpp \
src/test/allocator_tests.cpp \
src/test/base32_tests.cpp \
src/test/base58_tests.cpp \
src/test/base64_tests.cpp \
src/test/bip32_tests.cpp \
src/test/bloom_tests.cpp \
src/test/checkblock_tests.cpp \
src/test/Checkpoints_tests.cpp \
src/test/coins_tests.cpp \
src/test/compress_tests.cpp \
src/test/crypto_tests.cpp \
src/test/DoS_tests.cpp \
src/test/getarg_tests.cpp \
src/test/hash_tests.cpp \
src/test/key_tests.cpp \
src/test/main_tests.cpp \
src/test/mempool_tests.cpp \
src/test/miner_tests.cpp \
src/test/mruset_tests.cpp \
src/test/multisig_tests.cpp \
src/test/netbase_tests.cpp \
src/test/pmt_tests.cpp \
src/test/rpc_tests.cpp \
src/test/rpc_wallet_tests.cpp \
src/test/sanity_tests.cpp \
src/test/script_P2SH_tests.cpp \
src/test/script_tests.cpp \
src/test/scriptnum_tests.cpp \
src/test/serialize_tests.cpp \
src/test/sighash_tests.cpp \
src/test/sigopcount_tests.cpp \
src/test/skiplist_tests.cpp \
src/test/test_agrarian.cpp \
src/test/timedata_tests.cpp \
src/test/transaction_tests.cpp \
src/test/uint256_tests.cpp \
src/test/univalue_tests.cpp \
src/test/util_tests.cpp \
src/test/wallet_tests.cpp \
src/univalue/gen.cpp \
src/univalue/univalue.cpp \
src/univalue/univalue_read.cpp \
src/univalue/univalue_write.cpp \
src/leveldb/db/autocompact_test.cc \
src/leveldb/db/builder.cc \
src/leveldb/db/c.cc \
src/leveldb/db/c_test.c \
src/leveldb/db/corruption_test.cc \
src/leveldb/db/db_bench.cc \
src/leveldb/db/db_impl.cc \
src/leveldb/db/db_iter.cc \
src/leveldb/db/db_test.cc \
src/leveldb/db/dbformat.cc \
src/leveldb/db/dbformat_test.cc \
src/leveldb/db/dumpfile.cc \
src/leveldb/db/filename.cc \
src/leveldb/db/filename_test.cc \
src/leveldb/db/leveldb_main.cc \
src/leveldb/db/log_reader.cc \
src/leveldb/db/log_test.cc \
src/leveldb/db/log_writer.cc \
src/leveldb/db/memtable.cc \
src/leveldb/db/repair.cc \
src/leveldb/db/skiplist_test.cc \
src/leveldb/db/table_cache.cc \
src/leveldb/db/version_edit.cc \
src/leveldb/db/version_edit_test.cc \
src/leveldb/db/version_set.cc \
src/leveldb/db/version_set_test.cc \
src/leveldb/db/write_batch.cc \
src/leveldb/db/write_batch_test.cc \
src/leveldb/issues/issue178_test.cc \
src/leveldb/issues/issue200_test.cc \
src/leveldb/port/port_posix.cc \
src/leveldb/port/port_win.cc \
src/leveldb/table/block.cc \
src/leveldb/table/block_builder.cc \
src/leveldb/table/filter_block.cc \
src/leveldb/table/filter_block_test.cc \
src/leveldb/table/format.cc \
src/leveldb/table/iterator.cc \
src/leveldb/table/merger.cc \
src/leveldb/table/table.cc \
src/leveldb/table/table_builder.cc \
src/leveldb/table/table_test.cc \
src/leveldb/table/two_level_iterator.cc \
src/leveldb/util/arena.cc \
src/leveldb/util/arena_test.cc \
src/leveldb/util/bloom.cc \
src/leveldb/util/bloom_test.cc \
src/leveldb/util/cache.cc \
src/leveldb/util/cache_test.cc \
src/leveldb/util/coding.cc \
src/leveldb/util/coding_test.cc \
src/leveldb/util/comparator.cc \
src/leveldb/util/crc32c.cc \
src/leveldb/util/crc32c_test.cc \
src/leveldb/util/env.cc \
src/leveldb/util/env_posix.cc \
src/leveldb/util/env_test.cc \
src/leveldb/util/env_win.cc \
src/leveldb/util/filter_policy.cc \
src/leveldb/util/hash.cc \
src/leveldb/util/hash_test.cc \
src/leveldb/util/histogram.cc \
src/leveldb/util/logging.cc \
src/leveldb/util/options.cc \
src/leveldb/util/status.cc \
src/leveldb/util/testharness.cc \
src/leveldb/util/testutil.cc \
src/qt/test/paymentservertests.cpp \
src/qt/test/test_main.cpp \
src/qt/test/uritests.cpp \
src/secp256k1/src/bench_inv.c \
src/secp256k1/src/bench_sign.c \
src/secp256k1/src/bench_verify.c \
src/secp256k1/src/secp256k1.c \
src/secp256k1/src/tests.c \
src/leveldb/doc/bench/db_bench_sqlite3.cc \
src/leveldb/doc/bench/db_bench_tree_db.cc \
src/leveldb/helpers/memenv/memenv.cc \
src/leveldb/helpers/memenv/memenv_test.cc \
src/secp256k1/src/java/org_bitcoin_NativeSecp256k1.c
RESOURCES += src/qt/agrarian.qrc src/qt/agrarian_locale.qrc
TRANSLATIONS += src/qt/locale/agrarian_bg.ts \
src/qt/locale/agrarian_de.ts \
src/qt/locale/agrarian_en.ts \
src/qt/locale/agrarian_es.ts \
src/qt/locale/agrarian_fi.ts \
src/qt/locale/agrarian_fr.ts \
src/qt/locale/agrarian_it.ts \
src/qt/locale/agrarian_ja.ts \
src/qt/locale/agrarian_pl.ts \
src/qt/locale/agrarian_pt.ts \
src/qt/locale/agrarian_ru.ts \
src/qt/locale/agrarian_sk.ts \
src/qt/locale/agrarian_sv.ts \
src/qt/locale/agrarian_vi.ts \
src/qt/locale/agrarian_zh_CN.ts \
src/qt/locale/agrarian_zh_TW.ts
+57
View File
@@ -0,0 +1,57 @@
# bash programmable completion for agrarian-tx(1)
# Copyright (c) 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
_agrarian_tx() {
local cur prev words=() cword
local agrarian_tx
# save and use original argument to invoke agrarian-tx for -help
# it might not be in $PATH
agrarian_tx="$1"
COMPREPLY=()
_get_comp_words_by_ref -n =: cur prev words cword
case "$cur" in
load=*:*)
cur="${cur#load=*:}"
_filedir
return 0
;;
*=*) # prevent attempts to complete other arguments
return 0
;;
esac
if [[ "$cword" == 1 || ( "$prev" != "-create" && "$prev" == -* ) ]]; then
# only options (or an uncompletable hex-string) allowed
# parse agrarian-tx -help for options
local helpopts
helpopts=$($agrarian_tx -help | sed -e '/^ -/ p' -e d )
COMPREPLY=( $( compgen -W "$helpopts" -- "$cur" ) )
else
# only commands are allowed
# parse -help for commands
local helpcmds
helpcmds=$($agrarian_tx -help | sed -e '1,/Commands:/d' -e 's/=.*/=/' -e '/^ [a-z]/ p' -e d )
COMPREPLY=( $( compgen -W "$helpcmds" -- "$cur" ) )
fi
# Prevent space if an argument is desired
if [[ $COMPREPLY == *= ]]; then
compopt -o nospace
fi
return 0
} &&
complete -F _agrarian_tx agrarian-tx
# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=sh
+56
View File
@@ -0,0 +1,56 @@
# bash programmable completion for agrariand(1) and agrarian-qt(1)
# Copyright (c) 2012-2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
_agrariand() {
local cur prev words=() cword
local agrariand
# save and use original argument to invoke agrariand for -help
# it might not be in $PATH
agrariand="$1"
COMPREPLY=()
_get_comp_words_by_ref -n = cur prev words cword
case "$cur" in
-conf=*|-pid=*|-loadblock=*|-rootcertificates=*|-rpccookiefile=*|-wallet=*)
cur="${cur#*=}"
_filedir
return 0
;;
-datadir=*)
cur="${cur#*=}"
_filedir -d
return 0
;;
-*=*) # prevent nonsense completions
return 0
;;
*)
# only parse -help if sensible
if [[ -z "$cur" || "$cur" =~ ^- ]]; then
local helpopts
helpopts=$($agrariand -help 2>&1 | awk '$1 ~ /^-/ { sub(/=.*/, "="); print $1 }' )
COMPREPLY=( $( compgen -W "$helpopts" -- "$cur" ) )
fi
# Prevent space if an argument is desired
if [[ $COMPREPLY == *= ]]; then
compopt -o nospace
fi
return 0
;;
esac
} &&
complete -F _agrariand agrariand agrarian-qt
# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=sh
+8
View File
@@ -0,0 +1,8 @@
### BitRPC
Allows for sending of all standard Bitcoin commands via RPC rather than as command line args.
### Looking for Wallet Tools?
BitRPC.py is able to do the exact same thing as `walletchangepass.py` and `walletunlock.py`. Their respective commands in BitRPC.py are:
bitrpc.py walletpassphrasechange
bitrpc.py walletpassphrase
+337
View File
@@ -0,0 +1,337 @@
from jsonrpc import ServiceProxy
import sys
import string
import getpass
# ===== BEGIN USER SETTINGS =====
# if you do not set these you will be prompted for a password for every command
rpcuser = ""
rpcpass = ""
# ====== END USER SETTINGS ======
if rpcpass == "":
access = ServiceProxy("http://127.0.0.1:51335")
else:
access = ServiceProxy("http://"+rpcuser+":"+rpcpass+"@127.0.0.1:51335")
cmd = sys.argv[1].lower()
if cmd == "backupwallet":
try:
path = raw_input("Enter destination path/filename: ")
print access.backupwallet(path)
except:
print "\n---An error occurred---\n"
elif cmd == "encryptwallet":
try:
pwd = getpass.getpass(prompt="Enter passphrase: ")
pwd2 = getpass.getpass(prompt="Repeat passphrase: ")
if pwd == pwd2:
access.encryptwallet(pwd)
print "\n---Wallet encrypted. Server stopping, restart to run with encrypted wallet---\n"
else:
print "\n---Passphrases do not match---\n"
except:
print "\n---An error occurred---\n"
elif cmd == "getaccount":
try:
addr = raw_input("Enter a Bitcoin address: ")
print access.getaccount(addr)
except:
print "\n---An error occurred---\n"
elif cmd == "getaccountaddress":
try:
acct = raw_input("Enter an account name: ")
print access.getaccountaddress(acct)
except:
print "\n---An error occurred---\n"
elif cmd == "getaddressesbyaccount":
try:
acct = raw_input("Enter an account name: ")
print access.getaddressesbyaccount(acct)
except:
print "\n---An error occurred---\n"
elif cmd == "getbalance":
try:
acct = raw_input("Enter an account (optional): ")
mc = raw_input("Minimum confirmations (optional): ")
try:
print access.getbalance(acct, mc)
except:
print access.getbalance()
except:
print "\n---An error occurred---\n"
elif cmd == "getblockbycount":
try:
height = raw_input("Height: ")
print access.getblockbycount(height)
except:
print "\n---An error occurred---\n"
elif cmd == "getblockcount":
try:
print access.getblockcount()
except:
print "\n---An error occurred---\n"
elif cmd == "getblocknumber":
try:
print access.getblocknumber()
except:
print "\n---An error occurred---\n"
elif cmd == "getconnectioncount":
try:
print access.getconnectioncount()
except:
print "\n---An error occurred---\n"
elif cmd == "getdifficulty":
try:
print access.getdifficulty()
except:
print "\n---An error occurred---\n"
elif cmd == "getgenerate":
try:
print access.getgenerate()
except:
print "\n---An error occurred---\n"
elif cmd == "gethashespersec":
try:
print access.gethashespersec()
except:
print "\n---An error occurred---\n"
elif cmd == "getinfo":
try:
print access.getinfo()
except:
print "\n---An error occurred---\n"
elif cmd == "getnewaddress":
try:
acct = raw_input("Enter an account name: ")
try:
print access.getnewaddress(acct)
except:
print access.getnewaddress()
except:
print "\n---An error occurred---\n"
elif cmd == "getreceivedbyaccount":
try:
acct = raw_input("Enter an account (optional): ")
mc = raw_input("Minimum confirmations (optional): ")
try:
print access.getreceivedbyaccount(acct, mc)
except:
print access.getreceivedbyaccount()
except:
print "\n---An error occurred---\n"
elif cmd == "getreceivedbyaddress":
try:
addr = raw_input("Enter a Bitcoin address (optional): ")
mc = raw_input("Minimum confirmations (optional): ")
try:
print access.getreceivedbyaddress(addr, mc)
except:
print access.getreceivedbyaddress()
except:
print "\n---An error occurred---\n"
elif cmd == "gettransaction":
try:
txid = raw_input("Enter a transaction ID: ")
print access.gettransaction(txid)
except:
print "\n---An error occurred---\n"
elif cmd == "getwork":
try:
data = raw_input("Data (optional): ")
try:
print access.gettransaction(data)
except:
print access.gettransaction()
except:
print "\n---An error occurred---\n"
elif cmd == "help":
try:
cmd = raw_input("Command (optional): ")
try:
print access.help(cmd)
except:
print access.help()
except:
print "\n---An error occurred---\n"
elif cmd == "listaccounts":
try:
mc = raw_input("Minimum confirmations (optional): ")
try:
print access.listaccounts(mc)
except:
print access.listaccounts()
except:
print "\n---An error occurred---\n"
elif cmd == "listreceivedbyaccount":
try:
mc = raw_input("Minimum confirmations (optional): ")
incemp = raw_input("Include empty? (true/false, optional): ")
try:
print access.listreceivedbyaccount(mc, incemp)
except:
print access.listreceivedbyaccount()
except:
print "\n---An error occurred---\n"
elif cmd == "listreceivedbyaddress":
try:
mc = raw_input("Minimum confirmations (optional): ")
incemp = raw_input("Include empty? (true/false, optional): ")
try:
print access.listreceivedbyaddress(mc, incemp)
except:
print access.listreceivedbyaddress()
except:
print "\n---An error occurred---\n"
elif cmd == "listtransactions":
try:
acct = raw_input("Account (optional): ")
count = raw_input("Number of transactions (optional): ")
frm = raw_input("Skip (optional):")
try:
print access.listtransactions(acct, count, frm)
except:
print access.listtransactions()
except:
print "\n---An error occurred---\n"
elif cmd == "move":
try:
frm = raw_input("From: ")
to = raw_input("To: ")
amt = raw_input("Amount:")
mc = raw_input("Minimum confirmations (optional): ")
comment = raw_input("Comment (optional): ")
try:
print access.move(frm, to, amt, mc, comment)
except:
print access.move(frm, to, amt)
except:
print "\n---An error occurred---\n"
elif cmd == "sendfrom":
try:
frm = raw_input("From: ")
to = raw_input("To: ")
amt = raw_input("Amount:")
mc = raw_input("Minimum confirmations (optional): ")
comment = raw_input("Comment (optional): ")
commentto = raw_input("Comment-to (optional): ")
try:
print access.sendfrom(frm, to, amt, mc, comment, commentto)
except:
print access.sendfrom(frm, to, amt)
except:
print "\n---An error occurred---\n"
elif cmd == "sendmany":
try:
frm = raw_input("From: ")
to = raw_input("To (in format address1:amount1,address2:amount2,...): ")
mc = raw_input("Minimum confirmations (optional): ")
comment = raw_input("Comment (optional): ")
try:
print access.sendmany(frm,to,mc,comment)
except:
print access.sendmany(frm,to)
except:
print "\n---An error occurred---\n"
elif cmd == "sendtoaddress":
try:
to = raw_input("To (in format address1:amount1,address2:amount2,...): ")
amt = raw_input("Amount:")
comment = raw_input("Comment (optional): ")
commentto = raw_input("Comment-to (optional): ")
try:
print access.sendtoaddress(to,amt,comment,commentto)
except:
print access.sendtoaddress(to,amt)
except:
print "\n---An error occurred---\n"
elif cmd == "setaccount":
try:
addr = raw_input("Address: ")
acct = raw_input("Account:")
print access.setaccount(addr,acct)
except:
print "\n---An error occurred---\n"
elif cmd == "setgenerate":
try:
gen= raw_input("Generate? (true/false): ")
cpus = raw_input("Max processors/cores (-1 for unlimited, optional):")
try:
print access.setgenerate(gen, cpus)
except:
print access.setgenerate(gen)
except:
print "\n---An error occurred---\n"
elif cmd == "settxfee":
try:
amt = raw_input("Amount:")
print access.settxfee(amt)
except:
print "\n---An error occurred---\n"
elif cmd == "stop":
try:
print access.stop()
except:
print "\n---An error occurred---\n"
elif cmd == "validateaddress":
try:
addr = raw_input("Address: ")
print access.validateaddress(addr)
except:
print "\n---An error occurred---\n"
elif cmd == "walletpassphrase":
try:
pwd = getpass.getpass(prompt="Enter wallet passphrase: ")
access.walletpassphrase(pwd, 60)
print "\n---Wallet unlocked---\n"
except:
print "\n---An error occurred---\n"
elif cmd == "walletpassphrasechange":
try:
pwd = getpass.getpass(prompt="Enter old wallet passphrase: ")
pwd2 = getpass.getpass(prompt="Enter new wallet passphrase: ")
access.walletpassphrasechange(pwd, pwd2)
print
print "\n---Passphrase changed---\n"
except:
print
print "\n---An error occurred---\n"
print
else:
print "Command not found or not supported"
+146
View File
@@ -0,0 +1,146 @@
# Author: sum01 <sum01@protonmail.com>
# Git: https://github.com/sum01/FindBerkeleyDB
# Read the README.md for the full info.
# Allow user to pass a path instead of guessing
if(BerkeleyDB_ROOT_DIR)
set(_BERKELEYDB_PATHS "${BerkeleyDB_ROOT_DIR}")
elseif(CMAKE_SYSTEM_NAME MATCHES ".*[wW]indows.*")
# MATCHES is used to work on any devies with windows in the name
# Shameless copy-paste from FindOpenSSL.cmake v3.8
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
list(APPEND _BERKELEYDB_HINTS "${_programfiles}")
# There's actually production release and version numbers in the file path.
# For example, if they're on v6.2.32: C:/Program Files/Oracle/Berkeley DB 12cR1 6.2.32/
# But this still works to find it, so I'm guessing it can accept partial path matches.
foreach(_TARGET_BERKELEYDB_PATH "Oracle/Berkeley DB" "Berkeley DB")
list(APPEND _BERKELEYDB_PATHS
"${_programfiles}/${_TARGET_BERKELEYDB_PATH}"
"C:/Program Files (x86)/${_TARGET_BERKELEYDB_PATH}"
"C:/Program Files/${_TARGET_BERKELEYDB_PATH}"
"C:/${_TARGET_BERKELEYDB_PATH}"
)
endforeach()
else()
# Paths for anything other than Windows
# Cellar/berkeley-db is for macOS from homebrew installation
list(APPEND _BERKELEYDB_PATHS
"/usr/local/Cellar/berkeley-db@4"
"/usr/local/Cellar/berkeley-db"
"/opt"
"/opt/local"
"/usr/local"
)
endif()
# Find includes path
find_path(BerkeleyDB_INCLUDE_DIRS
db_cxx.h
PATHS "${_BERKELEYDB_PATHS}"
PATH_SUFFIXES "include" "includes"
)
# Checks if the version file exists, save the version file to a var, and fail if there's no version file
if(BerkeleyDB_INCLUDE_DIRS)
# Read the version file db.h into a variable
file(READ "${BerkeleyDB_INCLUDE_DIRS}/db.h" _BERKELEYDB_DB_HEADER)
# Parse the DB version into variables to be used in the lib names
string(REGEX REPLACE ".*DB_VERSION_MAJOR ([0-9]+).*" "\\1" BerkeleyDB_VERSION_MAJOR "${_BERKELEYDB_DB_HEADER}")
string(REGEX REPLACE ".*DB_VERSION_MINOR ([0-9]+).*" "\\1" BerkeleyDB_VERSION_MINOR "${_BERKELEYDB_DB_HEADER}")
# Patch version example on non-crypto installs: x.x.xNC
string(REGEX REPLACE ".*DB_VERSION_PATCH ([0-9]+(NC)?).*" "\\1" BerkeleyDB_VERSION_PATCH "${_BERKELEYDB_DB_HEADER}")
else()
if(BerkeleyDB_FIND_REQUIRED)
# If the find_package(BerkeleyDB REQUIRED) was used, fail since we couldn't find the header
message(FATAL_ERROR "Failed to find Berkeley DB's header file \"db.h\"! Try setting \"BerkeleyDB_ROOT_DIR\" when initiating Cmake.")
elseif(NOT BerkeleyDB_FIND_QUIETLY)
message(WARNING "Failed to find Berkeley DB's header file \"db.h\"! Try setting \"BerkeleyDB_ROOT_DIR\" when initiating Cmake.")
endif()
# Set some garbage values to the versions since we didn't find a file to read
set(BerkeleyDB_VERSION_MAJOR "0")
set(BerkeleyDB_VERSION_MINOR "0")
set(BerkeleyDB_VERSION_PATCH "0")
endif()
# The actual returned/output version variable (the others can be used if needed)
set(BerkeleyDB_VERSION "${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}.${BerkeleyDB_VERSION_PATCH}")
# Finds the target library for berkeley db, since they all follow the same naming conventions
macro(findpackage_berkeleydb_get_lib _BERKELEYDB_OUTPUT_VARNAME _TARGET_BERKELEYDB_LIB)
# Different systems sometimes have a version in the lib name...
# and some have a dash or underscore before the versions.
# CMake recommends to put unversioned names before versioned names
find_library(${_BERKELEYDB_OUTPUT_VARNAME}
NAMES
"${_TARGET_BERKELEYDB_LIB}"
"lib${_TARGET_BERKELEYDB_LIB}"
"lib${_TARGET_BERKELEYDB_LIB}${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}"
"lib${_TARGET_BERKELEYDB_LIB}-${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}"
"lib${_TARGET_BERKELEYDB_LIB}_${BerkeleyDB_VERSION_MAJOR}.${BerkeleyDB_VERSION_MINOR}"
"lib${_TARGET_BERKELEYDB_LIB}${BerkeleyDB_VERSION_MAJOR}${BerkeleyDB_VERSION_MINOR}"
"lib${_TARGET_BERKELEYDB_LIB}-${BerkeleyDB_VERSION_MAJOR}${BerkeleyDB_VERSION_MINOR}"
"lib${_TARGET_BERKELEYDB_LIB}_${BerkeleyDB_VERSION_MAJOR}${BerkeleyDB_VERSION_MINOR}"
"lib${_TARGET_BERKELEYDB_LIB}${BerkeleyDB_VERSION_MAJOR}"
"lib${_TARGET_BERKELEYDB_LIB}-${BerkeleyDB_VERSION_MAJOR}"
"lib${_TARGET_BERKELEYDB_LIB}_${BerkeleyDB_VERSION_MAJOR}"
HINTS ${_BERKELEYDB_HINTS}
PATH_SUFFIXES "lib" "lib64" "libs" "libs64"
PATHS ${_BERKELEYDB_PATHS}
)
# If the library was found, add it to our list of libraries
if(${_BERKELEYDB_OUTPUT_VARNAME})
# If found, append to our libraries variable
# The ${{}} is because the first expands to target the real variable, the second expands the variable's contents...
# and the real variable's contents is the path to the lib. Thus, it appends the path of the lib to BerkeleyDB_LIBRARIES.
list(APPEND BerkeleyDB_LIBRARIES "${${_BERKELEYDB_OUTPUT_VARNAME}}")
endif()
endmacro()
# Find and set the paths of the specific library to the variable
findpackage_berkeleydb_get_lib(BerkeleyDB_LIBRARY "db")
# NOTE: Windows doesn't have a db_cxx lib, but instead compiles the cxx code into the "db" lib
findpackage_berkeleydb_get_lib(BerkeleyDB_Cxx_LIBRARY "db_cxx")
# NOTE: I don't think Linux/Unix gets an SQL lib
findpackage_berkeleydb_get_lib(BerkeleyDB_Sql_LIBRARY "db_sql")
findpackage_berkeleydb_get_lib(BerkeleyDB_Stl_LIBRARY "db_stl")
# Needed for find_package_handle_standard_args()
include(FindPackageHandleStandardArgs)
# Fails if required vars aren't found, or if the version doesn't meet specifications.
find_package_handle_standard_args(BerkeleyDB
FOUND_VAR BerkeleyDB_FOUND
REQUIRED_VARS
BerkeleyDB_INCLUDE_DIRS
BerkeleyDB_LIBRARY
VERSION_VAR BerkeleyDB_VERSION
)
# Create an imported lib for easy linking by external projects
if(BerkeleyDB_FOUND AND BerkeleyDB_LIBRARIES AND NOT TARGET Oracle::BerkeleyDB)
add_library(Oracle::BerkeleyDB UNKNOWN IMPORTED)
set_target_properties(Oracle::BerkeleyDB PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${BerkeleyDB_INCLUDE_DIRS}"
IMPORTED_LOCATION "${BerkeleyDB_LIBRARY}"
INTERFACE_LINK_LIBRARIES "${BerkeleyDB_LIBRARIES}"
)
endif()
# Only show the includes path and libraries in the GUI if they click "advanced".
# Does nothing when using the CLI
mark_as_advanced(FORCE
BerkeleyDB_INCLUDE_DIRS
BerkeleyDB_LIBRARIES
BerkeleyDB_LIBRARY
BerkeleyDB_Cxx_LIBRARY
BerkeleyDB_Sql_LIBRARY
BerkeleyDB_Stl_LIBRARY
)
include(FindPackageMessage)
# A message that tells the user what includes/libs were found, and obeys the QUIET command.
find_package_message(BerkeleyDB
"Found BerkeleyDB libraries: ${BerkeleyDB_LIBRARIES}"
"[${BerkeleyDB_LIBRARIES}[${BerkeleyDB_INCLUDE_DIRS}]]"
)
+33
View File
@@ -0,0 +1,33 @@
# - Find GMP
# This module defines
# GMP_INCLUDE_DIR, where to find GMP headers
# GMP_LIBRARY, LibEvent libraries
# GMP_FOUND, If false, do not try to use GMP
set(GMP_PREFIX "" CACHE PATH "path ")
find_path(GMP_INCLUDE_DIR gmp.h gmpxx.h
PATHS ${GMP_PREFIX}/include /usr/include /usr/local/include )
find_library(GMP_LIBRARY NAMES gmp libgmp
PATHS ${GMP_PREFIX}/lib /usr/lib /usr/local/lib)
if(GMP_INCLUDE_DIR AND GMP_LIBRARY)
get_filename_component(GMP_LIBRARY_DIR ${GMP_LIBRARY} PATH)
set(GMP_FOUND TRUE)
endif()
if(GMP_FOUND)
if(NOT GMP_FIND_QUIETLY)
MESSAGE(STATUS "Found GMP: ${GMP_LIBRARY}")
endif()
elseif(GMP_FOUND)
if(GMP_FIND_REQUIRED)
message(FATAL_ERROR "Could not find GMP")
endif()
endif()
mark_as_advanced(
GMP_LIB
GMP_INCLUDE_DIR
)
+44
View File
@@ -0,0 +1,44 @@
# - Find LibEvent (a cross event library)
# This module defines
# LIBEVENT_INCLUDE_DIR, where to find LibEvent headers
# LIBEVENT_LIB, LibEvent libraries
# LibEvent_FOUND, If false, do not try to use libevent
if(($ENV{triple}) AND (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}"))
set(LIBEVENT_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/include")
set(LIBEVENT_LIB "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/lib/libevent.a")
set(LIBEVENT_PTHREAD_LIB "${CMAKE_CURRENT_SOURCE_DIR}/depends/$ENV{triple}/lib/libevent.a")
else()
set(LibEvent_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}")
foreach(prefix ${LibEvent_EXTRA_PREFIXES})
list(APPEND LibEvent_INCLUDE_PATHS "${prefix}/include")
list(APPEND LibEvent_LIB_PATHS "${prefix}/lib")
endforeach()
find_path(LIBEVENT_INCLUDE_DIR event.h PATHS ${LibEvent_INCLUDE_PATHS})
find_library(LIBEVENT_LIB NAMES event PATHS ${LibEvent_LIB_PATHS})
find_library(LIBEVENT_PTHREAD_LIB NAMES event_pthreads PATHS ${LibEvent_LIB_PATHS})
endif()
if (LIBEVENT_LIB AND LIBEVENT_INCLUDE_DIR AND LIBEVENT_PTHREAD_LIB)
set(LibEvent_FOUND TRUE)
set(LIBEVENT_LIB ${LIBEVENT_LIB} ${LIBEVENT_PTHREAD_LIB})
else ()
set(LibEvent_FOUND FALSE)
endif ()
if (LibEvent_FOUND)
if (NOT LibEvent_FIND_QUIETLY)
message(STATUS "Found libevent: ${LIBEVENT_LIB}")
endif ()
else ()
if (LibEvent_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find libevent and libevent_pthread.")
endif ()
message(STATUS "libevent and libevent_pthread NOT found.")
endif ()
mark_as_advanced(
LIBEVENT_LIB
LIBEVENT_INCLUDE_DIR
)
+37
View File
@@ -0,0 +1,37 @@
# - Find Qrcode
# This module defines
# QRCODE_INCLUDE_DIR, where to find libqrencode headers
# QRCODE_LIB, libqrencode libraries
# QRCODE_FOUND, If false, do not try to use libqrencode
set(QRCODE_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}")
foreach(prefix ${ZMQ_EXTRA_PREFIXES})
list(APPEND QRCODE_INCLUDE_PATHS "${prefix}/include")
list(APPEND QRCODE_LIB_PATHS "${prefix}/lib")
endforeach()
find_path(QRCODE_INCLUDE_DIR qrencode.h PATHS ${QRCODE_INCLUDE_PATHS})
find_library(QRCODE_LIB NAMES qrencode PATHS ${QRCODE_LIB_PATHS})
if (QRCODE_LIB AND QRCODE_INCLUDE_DIR)
set(QRCODE_FOUND TRUE)
else ()
set(QRCODE_FOUND FALSE)
endif ()
if (QRCODE_FOUND)
if (NOT QRCODE_FIND_QUIETLY)
message(STATUS "Found libqrencode: ${QRCODE_LIB}")
include_directories(${QRCODE_INCLUDE_DIR})
endif ()
else ()
if (QRCODE_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find libqrencode.")
endif ()
message(STATUS "libqrencode NOT found.")
endif ()
mark_as_advanced(
QRCODE_LIB
QRCODE_INCLUDE_DIR
)
+37
View File
@@ -0,0 +1,37 @@
# - Find ZeroMQ
# This module defines
# ZMQ_INCLUDE_DIR, where to find ZMQ headers
# ZMQ_LIB, ZMQ libraries
# ZMQ_FOUND, If false, do not try to use ZeroMQ
set(ZMQ_EXTRA_PREFIXES /usr/local /opt/local "$ENV{HOME}")
foreach(prefix ${ZMQ_EXTRA_PREFIXES})
list(APPEND ZMQ_INCLUDE_PATHS "${prefix}/include")
list(APPEND ZMQ_LIB_PATHS "${prefix}/lib")
endforeach()
find_path(ZMQ_INCLUDE_DIR zmq.h PATHS ${ZMQ_INCLUDE_PATHS})
find_library(ZMQ_LIB NAMES zmq PATHS ${ZMQ_LIB_PATHS})
if (ZMQ_LIB AND ZMQ_INCLUDE_DIR)
set(ZMQ_FOUND TRUE)
else ()
set(ZMQ_FOUND FALSE)
endif ()
if (ZMQ_FOUND)
if (NOT ZMQ_FIND_QUIETLY)
message(STATUS "Found ZeroMQ: ${ZMQ_LIB}")
include_directories(${ZMQ_INCLUDE_DIR})
endif ()
else ()
if (ZMQ_FIND_REQUIRED)
message(FATAL_ERROR "Could NOT find ZeroMQ.")
endif ()
message(STATUS "ZeroMQ NOT found.")
endif ()
mark_as_advanced(
ZMQ_LIB
ZMQ_INCLUDE_DIR
)
+21
View File
@@ -0,0 +1,21 @@
Debian
====================
This directory contains files used to package agrariand/agrarian-qt
for Debian-based Linux systems. If you compile agrariand/agrarian-qt yourself, there are some useful files here.
## agrarian: URI support ##
agrarian-qt.desktop (Gnome / Open Desktop)
To install:
sudo desktop-file-install agrarian-qt.desktop
sudo update-desktop-database
If you build yourself, you will either need to modify the paths in
the .desktop file or copy or symlink your agrarian-qt binary to `/usr/bin`
and the `../../share/pixmaps/agrarian128.png` to `/usr/share/pixmaps`
agrarian-qt.protocol (KDE)
+13
View File
@@ -0,0 +1,13 @@
[Desktop Entry]
Version=1.0
Name=Agrarian Core
Comment=Agrarian P2P Cryptocurrency
Comment[fr]=Agrarian, monnaie virtuelle cryptographique pair à pair
Comment[tr]=Agrarian, eşten eşe kriptografik sanal para birimi
Exec=agrarian-qt %u
Terminal=false
Type=Application
Icon=agrarian128
MimeType=x-scheme-handler/agrarian;
Categories=Office;Finance;
StartupWMClass=Agrarian-qt
+6
View File
@@ -0,0 +1,6 @@
usr/local/bin/agrarian-qt usr/bin
share/pixmaps/agrarian32.xpm usr/share/pixmaps
share/pixmaps/agrarian16.xpm usr/share/pixmaps
share/pixmaps/agrarian128.png usr/share/pixmaps
debian/agrarian-qt.desktop usr/share/applications
debian/agrarian-qt.protocol usr/share/kde4/services/
@@ -0,0 +1,2 @@
# Linked code is Expat - only Debian packaging is GPL-2+
agrarian-qt: possible-gpl-code-linked-with-openssl
+1
View File
@@ -0,0 +1 @@
doc/man/agrarian-qt.1
+11
View File
@@ -0,0 +1,11 @@
[Protocol]
exec=agrarian-qt '%u'
protocol=agrarian
input=none
output=none
helper=true
listing=
reading=false
writing=false
makedir=false
deleting=false
+2
View File
@@ -0,0 +1,2 @@
contrib/agrariand.bash-completion agrariand
contrib/agrarian-cli.bash-completion agrarian-cli
+1
View File
@@ -0,0 +1 @@
debian/examples/agrarian.conf
+3
View File
@@ -0,0 +1,3 @@
usr/local/bin/agrariand usr/bin
usr/local/bin/agrarian-cli usr/bin
debian/examples/agrarian.conf etc/agrarian
@@ -0,0 +1,2 @@
# Linked code is Expat - only Debian packaging is GPL-2+
agrariand: possible-gpl-code-linked-with-openssl
+2
View File
@@ -0,0 +1,2 @@
doc/man/agrariand.1
doc/man/agrarian-cli.1
+28
View File
@@ -0,0 +1,28 @@
#!/bin/sh
# setup agrarian account, homedir etc
set -e
BCUSER="agrarian"
BCHOME="/var/lib/agrarian"
if [ "$1" = "configure" ]; then
# Add agrarian user/group - this will gracefully abort if the user already exists.
# A homedir is never created.
set +e
adduser --system --home "${BCHOME}" --no-create-home --group "${BCUSER}" 2>/dev/null
set -e
# If the homedir does not already exist, create it with proper
# ownership and permissions.
if [ ! -d "${BCHOME}" ]; then
mkdir -m 0750 -p "${BCHOME}"
chown "${BCUSER}:${BCUSER}" "${BCHOME}"
fi
fi
#DEBHELPER#
exit 0
+35
View File
@@ -0,0 +1,35 @@
#!/bin/sh
# setup agrarian account, homedir etc
set -e
BCUSER="agrarian"
BCHOME="/var/lib/agrarian"
if [ "$1" = "purge" ]; then
# The agrarian user is left in place for now - This is to ensure that a new user
# will not inherit the users UID/GID and inadvertently gain access to wallets etc
# The homedir is also left intact to ensure that we don't accidentally delete a
# wallet or something equally important
echo
echo "#"
echo "# The agrarian user (${BCUSER}) and data dir (${BCHOME})"
echo "# were left intact."
echo "#"
echo "# Make sure to check \"${BCHOME}\" for wallets and other"
echo "# important bits."
echo "#"
echo "# After backing up all vital data, cleanup can be completed"
echo "# by running: sudo userdel -r ${BCUSER}"
echo "#"
echo
fi
#DEBHELPER#
exit 0
+45
View File
@@ -0,0 +1,45 @@
# It is not recommended to modify this file in-place, because it will
# be overwritten during package upgrades. If you want to add further
# options or overwrite existing ones then use
# $ systemctl edit agrariand.service
# See "man systemd.service" for details.
# Note that almost all daemon options could be specified in
# /etc/agrarian/agrarian.conf
[Unit]
Description=Agrarian daemon
After=network.target
[Service]
ExecStart=/usr/bin/agrariand -daemon -datadir=/var/lib/agrarian -conf=/etc/agrarian/agrarian.conf -pid=/run/agrariand/agrariand.pid
# Creates /run/agrariand owned by agrarian
RuntimeDirectory=agrariand
User=agrarian
Type=forking
PIDFile=/run/agrariand/agrariand.pid
Restart=on-failure
# Hardening measures
####################
# Provide a private /tmp and /var/tmp.
PrivateTmp=true
# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full
# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true
# Use a new /dev namespace only populated with API pseudo devices
# such as /dev/null, /dev/zero and /dev/random.
PrivateDevices=true
# Deny the creation of writable and executable memory mappings.
# Commented out as it's not supported on Debian 8 or Ubuntu 16.04 LTS
#MemoryDenyWriteExecute=true
[Install]
WantedBy=multi-user.target
+5
View File
@@ -0,0 +1,5 @@
agrarian (3.2.0-trusty1) trusty; urgency=medium
* Agrarian Core v3.2.0 (trusty).
-- Fuzzbawls Fri, 12 Apr 2019 12:01:00 -0700
+1
View File
@@ -0,0 +1 @@
7
+64
View File
@@ -0,0 +1,64 @@
Source: agrarian
Section: utils
Priority: optional
Maintainer: Fuzzbawls <fuzzbawls@gmail.com>
Uploaders: Fuzzbawls <fuzzbawls@gmail.com>
Build-Depends: debhelper,
devscripts,
automake,
libtool,
bash-completion,
libdb4.8++-dev,
libssl1.0-dev | libssl-dev,
pkg-config,
libevent-dev,
libgmp-dev,
libboost-system1.48-dev | libboost-system-dev (>> 1.47),
libboost-filesystem1.48-dev | libboost-filesystem-dev (>> 1.47),
libboost-program-options1.48-dev | libboost-program-options-dev (>> 1.47),
libboost-thread1.48-dev | libboost-thread-dev (>> 1.47),
libboost-test1.48-dev | libboost-test-dev (>> 1.47),
libboost-chrono1.48-dev | libboost-chrono-dev (>> 1.47),
libminiupnpc8-dev | libminiupnpc-dev,
xvfb,
qtbase5-dev, qttools5-dev-tools, qttools5-dev,
libqrencode-dev,
libprotobuf-dev, protobuf-compiler,
python,
libzmq3-dev,
dh-systemd
Standards-Version: 3.9.2
Homepage: http://www.agrarian.org
Vcs-Git: git://github.com/Agrarian-Project/Agrarian.git
Vcs-Browser: http://github.com/Agrarian-Project/Agrarian
Package: agrariand
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: peer-to-peer network based digital currency - daemon
Agrarian is a free open source peer-to-peer electronic cash system that
is completely decentralized, without the need for a central server or
trusted parties. Users hold the crypto keys to their own money and
transact directly with each other, with the help of a P2P network to
check for double-spending.
.
Full transaction history is stored locally at each client. This
requires 10+ GB of space, slowly growing.
.
This package provides the daemon, agrariand, and the CLI tool
agrarian-cli to interact with the daemon.
Package: agrarian-qt
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: peer-to-peer network based digital currency - Qt GUI
Agrarian is a free open source peer-to-peer electronic cash system that
is completely decentralized, without the need for a central server or
trusted parties. Users hold the crypto keys to their own money and
transact directly with each other, with the help of a P2P network to
check for double-spending.
.
Full transaction history is stored locally at each client. This
requires 10+ GB of space, slowly growing.
.
This package provides Agrarian-Qt, a GUI for Agrarian based on Qt.
+165
View File
@@ -0,0 +1,165 @@
Format: http://svn.debian.org/wsvn/dep/web/deps/dep5.mdwn?rev=174
Upstream-Name: Bitcoin
Upstream-Contact: Satoshi Nakamoto <satoshin@gmx.com>
irc://#bitcoin@freenode.net
Source: https://github.com/bitcoin/bitcoin
Files: *
Copyright: 2009-2012, Bitcoin Core Developers
License: Expat
Comment: The Bitcoin Core Developers encompasses the current developers listed on bitcoin.org,
as well as the numerous contributors to the project.
Files: src/json/*
Copyright: 2007-2009, John W. Wilkinson
License: Expat
Files: src/strlcpy.h
Copyright: 1998, Todd C. Miller <Todd.Miller@courtesan.com>
License: ISC
Files: debian/*
Copyright: 2010-2011, Jonas Smedegaard <dr@jones.dk>
2011, Matt Corallo <matt@bluematt.me>
License: GPL-2+
Files: debian/manpages/*
Copyright: Micah Anderson <micah@debian.org>
License: GPL-3+
Files: src/qt/res/icons/clock*.png, src/qt/res/icons/tx*.png,
src/qt/res/src/*.svg
Copyright: Wladimir van der Laan
License: Expat
Files: src/qt/res/icons/address-book.png, src/qt/res/icons/export.png,
src/qt/res/icons/history.png, src/qt/res/icons/key.png,
src/qt/res/icons/lock_*.png, src/qt/res/icons/overview.png,
src/qt/res/icons/receive.png, src/qt/res/icons/send.png,
src/qt/res/icons/synced.png, src/qt/res/icons/filesave.png
Copyright: David Vignoni (david@icon-king.com)
ICON KING - www.icon-king.com
License: LGPL
Comment: NUVOLA ICON THEME for KDE 3.x
Original icons: kaddressbook, klipper_dock, view-list-text,
key-password, encrypted/decrypted, go-home, go-down,
go-next, dialog-ok
Site: http://www.icon-king.com/projects/nuvola/
Files: src/qt/res/icons/connect*.png
Copyright: schollidesign
License: GPL-3+
Comment: Icon Pack: Human-O2
Site: http://findicons.com/icon/93743/blocks_gnome_netstatus_0
Files: src/qt/res/icons/transaction*.png
Copyright: md2k7
License: Expat
Comment: Site: https://bitcointalk.org/index.php?topic=15276.0
Files: src/qt/res/icons/configure.png, src/qt/res/icons/quit.png,
src/qt/res/icons/editcopy.png, src/qt/res/icons/editpaste.png,
src/qt/res/icons/add.png, src/qt/res/icons/edit.png,
src/qt/res/icons/remove.png
Copyright: http://www.everaldo.com
License: LGPL
Comment: Icon Pack: Crystal SVG
Files: src/qt/res/icons/bitcoin.png, src/qt/res/icons/toolbar.png
Copyright: Bitboy (optimized for 16x16 by Wladimir van der Laan)
License: PUB-DOM
Comment: Site: https://bitcointalk.org/?topic=1756.0
Files: scripts/img/reload.xcf, src/qt/res/movies/*.png
Copyright: Everaldo (Everaldo Coelho)
License: GPL-3+
Comment: Icon Pack: Kids
Site: http://findicons.com/icon/17102/reload?id=17102
Files: src/qt/res/images/splash2.jpg
License: PUB-DOM
Copyright: Crobbo (forum)
Comment: Site: https://bitcointalk.org/index.php?topic=32273.0
License: Expat
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
License: ISC
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR
BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
License: GPL-2+
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 2, 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.
Comment:
On Debian systems the GNU General Public License (GPL) version 2 is
located in '/usr/share/common-licenses/GPL-2'.
.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
License: GPL-3+
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU General Public License, Version 3 or any
later version published by the Free Software Foundation.
Comment:
On Debian systems the GNU General Public License (GPL) version 3 is
located in '/usr/share/common-licenses/GPL-3'.
.
You should have received a copy of the GNU General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
License: LGPL
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.
Comment:
On Debian systems the GNU Lesser General Public License (LGPL) is
located in '/usr/share/common-licenses/LGPL'.
.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
License: PUB-DOM
This work is in the public domain.
+105
View File
@@ -0,0 +1,105 @@
##
## agrarian.conf configuration file. Lines beginning with # are comments.
##
# Network-related settings:
# Run on the test network instead of the real agrarian network.
#testnet=0
# Run a regression test network
#regtest=0
# Connect via a SOCKS5 proxy
#proxy=127.0.0.1:9050
##############################################################
## Quick Primer on addnode vs connect ##
## Let's say for instance you use addnode=4.2.2.4 ##
## addnode will connect you to and tell you about the ##
## nodes connected to 4.2.2.4. In addition it will tell ##
## the other nodes connected to it that you exist so ##
## they can connect to you. ##
## connect will not do the above when you 'connect' to it. ##
## It will *only* connect you to 4.2.2.4 and no one else.##
## ##
## So if you're behind a firewall, or have other problems ##
## finding nodes, add some using 'addnode'. ##
## ##
## If you want to stay private, use 'connect' to only ##
## connect to "trusted" nodes. ##
## ##
## If you run multiple nodes on a LAN, there's no need for ##
## all of them to open lots of connections. Instead ##
## 'connect' them all to one node that is port forwarded ##
## and has lots of connections. ##
## Thanks goes to [Noodle] on Freenode. ##
##############################################################
# Use as many addnode= settings as you like to connect to specific peers
#addnode=69.164.218.197
#addnode=10.0.0.2:51336
# Alternatively use as many connect= settings as you like to connect ONLY to specific peers
#connect=69.164.218.197
#connect=10.0.0.1:51336
# Listening mode, enabled by default except when 'connect' is being used
#listen=1
# Maximum number of inbound+outbound connections.
#maxconnections=
#
# JSON-RPC options (for controlling a running Agrarian/agrariand process)
#
# server=1 tells Agrarian-QT and agrariand to accept JSON-RPC commands
#server=0
# You must set rpcuser and rpcpassword to secure the JSON-RPC api
#rpcuser=Ulysseys
#rpcpassword=YourSuperGreatPasswordNumber_DO_NOT_USE_THIS_OR_YOU_WILL_GET_ROBBED_385593
# How many seconds agrarian will wait for a complete RPC HTTP request.
# after the HTTP connection is established.
#rpcclienttimeout=30
# By default, only RPC connections from localhost are allowed.
# Specify as many rpcallowip= settings as you like to allow connections from other hosts,
# either as a single IPv4/IPv6 or with a subnet specification.
# NOTE: opening up the RPC port to hosts outside your local trusted network is NOT RECOMMENDED,
# because the rpcpassword is transmitted over the network unencrypted.
# server=1 tells Agrarian-QT to accept JSON-RPC commands.
# it is also read by agrariand to determine if RPC should be enabled
#rpcallowip=10.1.1.34/255.255.255.0
#rpcallowip=1.2.3.4/24
#rpcallowip=2001:db8:85a3:0:0:8a2e:370:7334/96
# Listen for RPC connections on this TCP port:
#rpcport=51335
# You can use Agrarian or agrariand to send commands to Agrarian/agrariand
# running on another host using this option:
#rpcconnect=127.0.0.1
# Miscellaneous options
# Pre-generate this many public/private key pairs, so wallet backups will be valid for
# both prior transactions and several dozen future transactions.
#keypool=100
# Pay an optional transaction fee every time you send AGRs. Transactions with fees
# are more likely than free transactions to be included in generated blocks, so may
# be validated sooner.
#paytxfee=0.00
# User interface options
# Start Agrarian minimized
#min=1
# Minimize to the system tray
#minimizetotray=1
+5
View File
@@ -0,0 +1,5 @@
# Configuration file for git-buildpackage and friends
[DEFAULT]
pristine-tar = True
sign-tags = True
+3
View File
@@ -0,0 +1,3 @@
0xxx: Grabbed from upstream development.
1xxx: Possibly relevant for upstream adoption.
2xxx: Only relevant for official Debian release.
+1
View File
@@ -0,0 +1 @@
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/make -f
# -*- mode: makefile; coding: utf-8 -*-
#DEB_MAKE_CHECK_TARGET = test_agrarian
#build/bitcoind::
# $(if $(filter nocheck,$(DEB_BUILD_OPTIONS)),,src/test_agrarian)
DEB_INSTALL_EXAMPLES_bitcoind += debian/examples/*
DEB_INSTALL_MANPAGES_bitcoind += debian/manpages/*
%:
dh --with bash-completion $@
override_dh_auto_clean:
if [ -f Makefile ]; then $(MAKE) distclean; fi
rm -rf Makefile.in aclocal.m4 configure src/Makefile.in src/agrarian-config.h.in src/build-aux src/qt/Makefile.in src/qt/test/Makefile.in src/test/Makefile.in
# Yea, autogen should be run on the source archive, but I like doing git archive
override_dh_auto_configure:
./autogen.sh
./configure --with-gui=qt5
override_dh_auto_test:
make check
# No SysV or Upstart init scripts included
override_dh_installinit:
dh_installinit \
--noscripts
# Dont enable service by default
override_dh_systemd_enable:
dh_systemd_enable \
--no-enable
# Restart after upgrade
override_dh_systemd_start:
dh_systemd_start \
+1
View File
@@ -0,0 +1 @@
3.0 (quilt)
+5
View File
@@ -0,0 +1,5 @@
# Run the "uscan" command to check for upstream updates and more.
version=3
# use qa.debian.org redirector; see man uscan
opts=uversionmangle=s/(\d)(alpha|beta|rc)/$1~$2/,dversionmangle=s/~dfsg\d*// \
http://githubredir.debian.net/github/agrarian-project/agrarian v(.*).tar.gz
+210
View File
@@ -0,0 +1,210 @@
Contents
========
This directory contains tools for developers working on this repository.
check-doc.py
============
Check if all command line args are documented. The return value indicates the
number of undocumented args.
clang-format-diff.py
===================
A script to format unified git diffs according to [.clang-format](../../src/.clang-format).
Requires `clang-format`, installed e.g. via `brew install clang-format` on macOS.
For instance, to format the last commit with 0 lines of context,
the script should be called from the git root folder as follows.
```
git diff -U0 HEAD~1.. | ./contrib/devtools/clang-format-diff.py -p1 -i -v
```
copyright\_header.py
====================
Provides utilities for managing copyright headers of `The PIVX
developers` in repository source files. It has three subcommands:
```
$ ./copyright_header.py report <base_directory> [verbose]
$ ./copyright_header.py update <base_directory>
$ ./copyright_header.py insert <file>
```
Running these subcommands without arguments displays a usage string.
copyright\_header.py report \<base\_directory\> [verbose]
---------------------------------------------------------
Produces a report of all copyright header notices found inside the source files
of a repository. Useful to quickly visualize the state of the headers.
Specifying `verbose` will list the full filenames of files of each category.
copyright\_header.py update \<base\_directory\> [verbose]
---------------------------------------------------------
Updates all the copyright headers of `The PIVX developers` which were
changed in a year more recent than is listed. For example:
```
// Copyright (c) <firstYear>-<lastYear> The PIVX developers
```
will be updated to:
```
// Copyright (c) <firstYear>-<lastModifiedYear> The PIVX developers
```
where `<lastModifiedYear>` is obtained from the `git log` history.
This subcommand also handles copyright headers that have only a single year. In
those cases:
```
// Copyright (c) <year> The PIVX developers
```
will be updated to:
```
// Copyright (c) <year>-<lastModifiedYear> The PIVX developers
```
where the update is appropriate.
copyright\_header.py insert \<file\>
------------------------------------
Inserts a copyright header for `The PIVX developers` at the top of the
file in either Python or C++ style as determined by the file extension. If the
file is a Python file and it has `#!` starting the first line, the header is
inserted in the line below it.
The copyright dates will be set to be `<year_introduced>-<current_year>` where
`<year_introduced>` is according to the `git log` history. If
`<year_introduced>` is equal to `<current_year>`, it will be set as a single
year rather than two hyphenated years.
If the file already has a copyright for `The PIVX developers`, the
script will exit.
gen-manpages.sh
===============
A small script to automatically create manpages in ../../doc/man by running the release binaries with the -help option.
This requires help2man which can be found at: https://www.gnu.org/software/help2man/
With in-tree builds this tool can be run from any directory within the
repostitory. To use this tool with out-of-tree builds set `BUILDDIR`. For
example:
```bash
BUILDDIR=$PWD/build contrib/devtools/gen-manpages.sh
```
github-merge.py
===============
A small script to automate merging pull-requests securely and sign them with GPG.
For example:
./github-merge.py 3077
(in any git repository) will help you merge pull request #3077 for the
Agrarian-Project/Agrarian repository.
What it does:
* Fetch master and the pull request.
* Locally construct a merge commit.
* Show the diff that merge results in.
* Ask you to verify the resulting source tree (so you can do a make
check or whatever).
* Ask you whether to GPG sign the merge commit.
* Ask you whether to push the result upstream.
This means that there are no potential race conditions (where a
pullreq gets updated while you're reviewing it, but before you click
merge), and when using GPG signatures, that even a compromised GitHub
couldn't mess with the sources.
Setup
---------
Configuring the github-merge tool for the Agrarian repository is done in the following way:
git config githubmerge.repository Agrarian-Project/Agrarian
git config githubmerge.testcmd "make -j4 check" (adapt to whatever you want to use for testing)
git config --global user.signingkey mykeyid
Authentication (optional)
--------------------------
The API request limit for unauthenticated requests is quite low, but the
limit for authenticated requests is much higher. If you start running
into rate limiting errors it can be useful to set an authentication token
so that the script can authenticate requests.
- First, go to [Personal access tokens](https://github.com/settings/tokens).
- Click 'Generate new token'.
- Fill in an arbitrary token description. No further privileges are needed.
- Click the `Generate token` button at the bottom of the form.
- Copy the generated token (should be a hexadecimal string)
Then do:
git config --global user.ghtoken "pasted token"
Create and verify timestamps of merge commits
---------------------------------------------
To create or verify timestamps on the merge commits, install the OpenTimestamps
client via `pip3 install opentimestamps-client`. Then, dowload the gpg wrapper
`ots-git-gpg-wrapper.sh` and set it as git's `gpg.program`. See
[the ots git integration documentation](https://github.com/opentimestamps/opentimestamps-client/blob/master/doc/git-integration.md#usage)
for further details.
optimize-pngs.py
================
A script to optimize png files in the Agrarian
repository (requires pngcrush).
security-check.py and test-security-check.py
============================================
Perform basic ELF security checks on a series of executables.
symbol-check.py
===============
A script to check that the (Linux) executables produced by gitian only contain
allowed gcc, glibc and libstdc++ version symbols. This makes sure they are
still compatible with the minimum supported Linux distribution versions.
Example usage after a gitian build:
find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py
If only supported symbols are used the return value will be 0 and the output will be empty.
If there are 'unsupported' symbols, the return value will be 1 a list like this will be printed:
.../64/test_agrarian: symbol memcpy from unsupported version GLIBC_2.14
.../64/test_agrarian: symbol __fdelt_chk from unsupported version GLIBC_2.15
.../64/test_agrarian: symbol std::out_of_range::~out_of_range() from unsupported version GLIBCXX_3.4.15
.../64/test_agrarian: symbol _ZNSt8__detail15_List_nod from unsupported version GLIBCXX_3.4.15
update-translations.py
======================
Run this script from the root of the repository to update all translations from transifex.
It will do the following automatically:
- fetch all translations
- post-process them into valid and committable format
- add missing translations to the build system (TODO)
See doc/translation-process.md for more information.
circular-dependencies.py
========================
Run this script from the root of the source tree (`src/`) to find circular dependencies in the source code.
This looks only at which files include other files, treating the `.cpp` and `.h` file as one unit.
Example usage:
cd .../src
../contrib/devtools/circular-dependencies.py {*,*/*,*/*/*}.{h,cpp}
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
This checks if all command line args are documented.
Return value is 0 to indicate no error.
Author: @MarcoFalke
'''
from subprocess import check_output
import re
import sys
FOLDER_GREP = 'src'
FOLDER_TEST = 'src/test/'
CMD_ROOT_DIR = '`git rev-parse --show-toplevel`/{}'.format(FOLDER_GREP)
CMD_GREP_ARGS = r"egrep -r -I '(map(Multi)?Args(\.count\(|\[)|Get(Bool)?Arg\()\"\-[^\"]+?\"' {} | grep -v '{}'".format(CMD_ROOT_DIR, FOLDER_TEST)
CMD_GREP_DOCS = r"egrep -r -I 'HelpMessageOpt\(\"\-[^\"=]+?(=|\")' {}".format(CMD_ROOT_DIR)
REGEX_ARG = re.compile(r'(?:map(?:Multi)?Args(?:\.count\(|\[)|Get(?:Bool)?Arg\()\"(\-[^\"]+?)\"')
REGEX_DOC = re.compile(r'HelpMessageOpt\(\"(\-[^\"=]+?)(?:=|\")')
# list unsupported, deprecated and duplicate args as they need no documentation
SET_DOC_OPTIONAL = set(['-rpcssl', '-benchmark', '-h', '-help', '-socks', '-tor', '-debugnet', '-whitelistalwaysrelay', '-prematurewitness', '-walletprematurewitness', '-promiscuousmempoolflags', '-blockminsize', '-sendfreetransactions', '-checklevel', '-liquidityprovider', '-anonymizeagrarianamount'])
def main():
used = check_output(CMD_GREP_ARGS, shell=True, universal_newlines=True)
docd = check_output(CMD_GREP_DOCS, shell=True, universal_newlines=True)
args_used = set(re.findall(re.compile(REGEX_ARG), used))
args_docd = set(re.findall(re.compile(REGEX_DOC), docd)).union(SET_DOC_OPTIONAL)
args_need_doc = args_used.difference(args_docd)
args_unknown = args_docd.difference(args_used)
print("Args used : {}".format(len(args_used)))
print("Args documented : {}".format(len(args_docd)))
print("Args undocumented: {}".format(len(args_need_doc)))
print(args_need_doc)
print("Args unknown : {}".format(len(args_unknown)))
print(args_unknown)
sys.exit(len(args_need_doc))
if __name__ == "__main__":
main()
+88
View File
@@ -0,0 +1,88 @@
#!/usr/bin/env python3
import sys
import re
MAPPING = {
'core_read.cpp': 'core_io.cpp',
'core_write.cpp': 'core_io.cpp',
}
# Directories with header-based modules, where the assumption that .cpp files
# define functions and variables declared in corresponding .h files is
# incorrect.
HEADER_MODULE_PATHS = [
'interfaces/'
]
def module_name(path):
if path in MAPPING:
path = MAPPING[path]
if any(path.startswith(dirpath) for dirpath in HEADER_MODULE_PATHS):
return path
if path.endswith(".h"):
return path[:-2]
if path.endswith(".c"):
return path[:-2]
if path.endswith(".cpp"):
return path[:-4]
return None
files = dict()
deps = dict()
RE = re.compile("^#include \"(.*)\"")
# Iterate over files, and create list of modules
for arg in sys.argv[1:]:
module = module_name(arg)
if module is None:
print("Ignoring file %s (does not constitute module)\n" % arg)
else:
files[arg] = module
deps[module] = set()
# Iterate again, and build list of direct dependencies for each module
# TODO: implement support for multiple include directories
for arg in sorted(files.keys()):
module = files[arg]
with open(arg, 'r', encoding="utf8") as f:
for line in f:
match = RE.match(line)
if match:
include = match.group(1)
included_module = module_name(include)
if included_module is not None and included_module in deps and included_module != module:
deps[module].add(included_module)
# Loop to find the shortest (remaining) circular dependency
have_cycle = False
while True:
shortest_cycle = None
for module in sorted(deps.keys()):
# Build the transitive closure of dependencies of module
closure = dict()
for dep in deps[module]:
closure[dep] = []
while True:
old_size = len(closure)
old_closure_keys = sorted(closure.keys())
for src in old_closure_keys:
for dep in deps[src]:
if dep not in closure:
closure[dep] = closure[src] + [src]
if len(closure) == old_size:
break
# If module is in its own transitive closure, it's a circular dependency; check if it is the shortest
if module in closure and (shortest_cycle is None or len(closure[module]) + 1 < len(shortest_cycle)):
shortest_cycle = [module] + closure[module]
if shortest_cycle is None:
break
# We have the shortest circular dependency; report it
module = shortest_cycle[0]
print("Circular dependency: %s" % (" -> ".join(shortest_cycle + [module])))
# And then break the dependency to avoid repeating in other cycles
deps[shortest_cycle[-1]] = deps[shortest_cycle[-1]] - set([module])
have_cycle = True
sys.exit(1 if have_cycle else 0)
+166
View File
@@ -0,0 +1,166 @@
#!/usr/bin/env python3
#
#===- clang-format-diff.py - ClangFormat Diff Reformatter ----*- python -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License.
#
# ============================================================
#
# University of Illinois/NCSA
# Open Source License
#
# Copyright (c) 2007-2015 University of Illinois at Urbana-Champaign.
# All rights reserved.
#
# Developed by:
#
# LLVM Team
#
# University of Illinois at Urbana-Champaign
#
# http://llvm.org
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal with
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimers.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimers in the
# documentation and/or other materials provided with the distribution.
#
# * Neither the names of the LLVM Team, University of Illinois at
# Urbana-Champaign, nor the names of its contributors may be used to
# endorse or promote products derived from this Software without specific
# prior written permission.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
# SOFTWARE.
#
# ============================================================
#
#===------------------------------------------------------------------------===#
r"""
ClangFormat Diff Reformatter
============================
This script reads input from a unified diff and reformats all the changed
lines. This is useful to reformat all the lines touched by a specific patch.
Example usage for git/svn users:
git diff -U0 HEAD^ | clang-format-diff.py -p1 -i
svn diff --diff-cmd=diff -x-U0 | clang-format-diff.py -i
"""
import argparse
import difflib
import io
import re
import subprocess
import sys
# Change this to the full path if clang-format is not on the path.
binary = 'clang-format'
def main():
parser = argparse.ArgumentParser(description=
'Reformat changed lines in diff. Without -i '
'option just output the diff that would be '
'introduced.')
parser.add_argument('-i', action='store_true', default=False,
help='apply edits to files instead of displaying a diff')
parser.add_argument('-p', metavar='NUM', default=0,
help='strip the smallest prefix containing P slashes')
parser.add_argument('-regex', metavar='PATTERN', default=None,
help='custom pattern selecting file paths to reformat '
'(case sensitive, overrides -iregex)')
parser.add_argument('-iregex', metavar='PATTERN', default=
r'.*\.(cpp|cc|c\+\+|cxx|c|cl|h|hpp|m|mm|inc|js|ts|proto'
r'|protodevel|java)',
help='custom pattern selecting file paths to reformat '
'(case insensitive, overridden by -regex)')
parser.add_argument('-sort-includes', action='store_true', default=False,
help='let clang-format sort include blocks')
parser.add_argument('-v', '--verbose', action='store_true',
help='be more verbose, ineffective without -i')
args = parser.parse_args()
# Extract changed lines for each file.
filename = None
lines_by_file = {}
for line in sys.stdin:
match = re.search('^\+\+\+\ (.*?/){%s}(\S*)' % args.p, line)
if match:
filename = match.group(2)
if filename is None:
continue
if args.regex is not None:
if not re.match('^%s$' % args.regex, filename):
continue
else:
if not re.match('^%s$' % args.iregex, filename, re.IGNORECASE):
continue
match = re.search('^@@.*\+(\d+)(,(\d+))?', line)
if match:
start_line = int(match.group(1))
line_count = 1
if match.group(3):
line_count = int(match.group(3))
if line_count == 0:
continue
end_line = start_line + line_count - 1
lines_by_file.setdefault(filename, []).extend(
['-lines', str(start_line) + ':' + str(end_line)])
# Reformat files containing changes in place.
for filename, lines in lines_by_file.items():
if args.i and args.verbose:
print('Formatting {}'.format(filename))
command = [binary, filename]
if args.i:
command.append('-i')
if args.sort_includes:
command.append('-sort-includes')
command.extend(lines)
command.extend(['-style=file', '-fallback-style=none'])
p = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=None,
stdin=subprocess.PIPE,
universal_newlines=True)
stdout, stderr = p.communicate()
if p.returncode != 0:
sys.exit(p.returncode)
if not args.i:
with open(filename, encoding="utf8") as f:
code = f.readlines()
formatted_code = io.StringIO(stdout).readlines()
diff = difflib.unified_diff(code, formatted_code,
filename, filename,
'(before formatting)', '(after formatting)')
diff_string = ''.join(diff)
if len(diff_string) > 0:
sys.stdout.write(diff_string)
if __name__ == '__main__':
main()
+46
View File
@@ -0,0 +1,46 @@
#!/bin/sh
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# This simple script checks for commits beginning with: scripted-diff:
# If found, looks for a script between the lines -BEGIN VERIFY SCRIPT- and
# -END VERIFY SCRIPT-. If no ending is found, it reads until the end of the
# commit message.
# The resulting script should exactly transform the previous commit into the current
# one. Any remaining diff signals an error.
if test "x$1" = "x"; then
echo "Usage: $0 <commit>..."
exit 1
fi
RET=0
PREV_BRANCH=`git name-rev --name-only HEAD`
PREV_HEAD=`git rev-parse HEAD`
for i in `git rev-list --reverse $1`; do
if git rev-list -n 1 --pretty="%s" $i | grep -q "^scripted-diff:"; then
git checkout --quiet $i^ || exit
SCRIPT="`git rev-list --format=%b -n1 $i | sed '/^-BEGIN VERIFY SCRIPT-$/,/^-END VERIFY SCRIPT-$/{//!b};d'`"
if test "x$SCRIPT" = "x"; then
echo "Error: missing script for: $i"
echo "Failed"
RET=1
else
echo "Running script for: $i"
echo "$SCRIPT"
eval "$SCRIPT"
git --no-pager diff --exit-code $i && echo "OK" || (echo "Failed"; false) || RET=1
fi
git reset --quiet --hard HEAD
else
if git rev-list "--format=%b" -n1 $i | grep -q '^-\(BEGIN\|END\)[ a-zA-Z]*-$'; then
echo "Error: script block marker but no scripted-diff in title"
echo "Failed"
RET=1
fi
fi
done
git checkout --quiet $PREV_BRANCH 2>/dev/null || git checkout --quiet $PREV_HEAD
exit $RET
+620
View File
@@ -0,0 +1,620 @@
#!/usr/bin/env python3
# Copyright (c) 2016-2018 The Bitcoin Core developers
# Copyright (c) 2018-2019 The PIVX developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import re
import fnmatch
import sys
import subprocess
import datetime
import os
################################################################################
# file filtering
################################################################################
EXCLUDE = [
# auto generated:
'src/qt/agrarianstrings.cpp',
'src/chainparamsseeds.h',
# other external copyrights:
'src/tinyformat.h',
'src/crypto/scrypt.cpp',
'test/functional/test_framework/bignum.py',
# python init:
'*__init__.py',
]
EXCLUDE_COMPILED = re.compile('|'.join([fnmatch.translate(m) for m in EXCLUDE]))
EXCLUDE_DIRS = [
# git subtrees
"src/crypto/ctaes/",
"src/leveldb/",
"src/secp256k1/",
"src/univalue/",
]
INCLUDE = ['*.h', '*.cpp', '*.cc', '*.c', '*.py']
INCLUDE_COMPILED = re.compile('|'.join([fnmatch.translate(m) for m in INCLUDE]))
def applies_to_file(filename):
for excluded_dir in EXCLUDE_DIRS:
if filename.startswith(excluded_dir):
return False
return ((EXCLUDE_COMPILED.match(filename) is None) and
(INCLUDE_COMPILED.match(filename) is not None))
################################################################################
# obtain list of files in repo according to INCLUDE and EXCLUDE
################################################################################
GIT_LS_CMD = 'git ls-files --full-name'.split(' ')
GIT_TOPLEVEL_CMD = 'git rev-parse --show-toplevel'.split(' ')
def call_git_ls(base_directory):
out = subprocess.check_output([*GIT_LS_CMD, base_directory])
return [f for f in out.decode("utf-8").split('\n') if f != '']
def call_git_toplevel():
"Returns the absolute path to the project root"
return subprocess.check_output(GIT_TOPLEVEL_CMD).strip().decode("utf-8")
def get_filenames_to_examine(base_directory):
"Returns an array of absolute paths to any project files in the base_directory that pass the include/exclude filters"
root = call_git_toplevel()
filenames = call_git_ls(base_directory)
return sorted([os.path.join(root, filename) for filename in filenames if
applies_to_file(filename)])
################################################################################
# define and compile regexes for the patterns we are looking for
################################################################################
COPYRIGHT_WITH_C = 'Copyright \(c\)'
COPYRIGHT_WITHOUT_C = 'Copyright'
ANY_COPYRIGHT_STYLE = '(%s|%s)' % (COPYRIGHT_WITH_C, COPYRIGHT_WITHOUT_C)
YEAR = "20[0-9][0-9]"
YEAR_RANGE = '(%s)(-%s)?' % (YEAR, YEAR)
YEAR_LIST = '(%s)(, %s)+' % (YEAR, YEAR)
ANY_YEAR_STYLE = '(%s|%s)' % (YEAR_RANGE, YEAR_LIST)
ANY_COPYRIGHT_STYLE_OR_YEAR_STYLE = ("%s %s" % (ANY_COPYRIGHT_STYLE,
ANY_YEAR_STYLE))
ANY_COPYRIGHT_COMPILED = re.compile(ANY_COPYRIGHT_STYLE_OR_YEAR_STYLE)
def compile_copyright_regex(copyright_style, year_style, name):
return re.compile('%s %s,? %s' % (copyright_style, year_style, name))
EXPECTED_HOLDER_NAMES = [
"Satoshi Nakamoto\n",
"The Bitcoin Core developers\n",
"The Bitcoin Core developers \n",
"Bitcoin Core Developers\n",
"the Bitcoin Core developers\n",
"The Bitcoin developers\n",
"The LevelDB Authors\. All rights reserved\.\n",
"BitPay Inc\.\n",
"BitPay, Inc\.\n",
"University of Illinois at Urbana-Champaign\.\n",
"MarcoFalke\n",
"Pieter Wuille\n",
"Pieter Wuille +\*\n",
"Pieter Wuille, Gregory Maxwell +\*\n",
"Pieter Wuille, Andrew Poelstra +\*\n",
"Ian Miers, Christina Garman and Matthew Green\n",
"Andrew Poelstra +\*\n",
"Wladimir J. van der Laan\n",
"Jeff Garzik\n",
"Diederik Huys, Pieter Wuille +\*\n",
"Thomas Daede, Cory Fields +\*\n",
"Jan-Klaas Kollhof\n",
"Sam Rushing\n",
"ArtForz -- public domain half-a-node\n",
" Projet RNRT SAPHIR\n",
"The Zcash developers\n",
"The Dash developers\n",
"The Dash Developers\n",
"The Dash Core developers\n",
"The Agrarian developers\n",
"The PPCoin developers\n",
]
DOMINANT_STYLE_COMPILED = {}
YEAR_LIST_STYLE_COMPILED = {}
WITHOUT_C_STYLE_COMPILED = {}
for holder_name in EXPECTED_HOLDER_NAMES:
DOMINANT_STYLE_COMPILED[holder_name] = (
compile_copyright_regex(COPYRIGHT_WITH_C, YEAR_RANGE, holder_name))
YEAR_LIST_STYLE_COMPILED[holder_name] = (
compile_copyright_regex(COPYRIGHT_WITH_C, YEAR_LIST, holder_name))
WITHOUT_C_STYLE_COMPILED[holder_name] = (
compile_copyright_regex(COPYRIGHT_WITHOUT_C, ANY_YEAR_STYLE,
holder_name))
################################################################################
# search file contents for copyright message of particular category
################################################################################
def get_count_of_copyrights_of_any_style_any_holder(contents):
return len(ANY_COPYRIGHT_COMPILED.findall(contents))
def file_has_dominant_style_copyright_for_holder(contents, holder_name):
match = DOMINANT_STYLE_COMPILED[holder_name].search(contents)
return match is not None
def file_has_year_list_style_copyright_for_holder(contents, holder_name):
match = YEAR_LIST_STYLE_COMPILED[holder_name].search(contents)
return match is not None
def file_has_without_c_style_copyright_for_holder(contents, holder_name):
match = WITHOUT_C_STYLE_COMPILED[holder_name].search(contents)
return match is not None
################################################################################
# get file info
################################################################################
def read_file(filename):
return open(filename, 'r', encoding="utf8").read()
def gather_file_info(filename):
info = {}
info['filename'] = filename
c = read_file(filename)
info['contents'] = c
info['all_copyrights'] = get_count_of_copyrights_of_any_style_any_holder(c)
info['classified_copyrights'] = 0
info['dominant_style'] = {}
info['year_list_style'] = {}
info['without_c_style'] = {}
for holder_name in EXPECTED_HOLDER_NAMES:
has_dominant_style = (
file_has_dominant_style_copyright_for_holder(c, holder_name))
has_year_list_style = (
file_has_year_list_style_copyright_for_holder(c, holder_name))
has_without_c_style = (
file_has_without_c_style_copyright_for_holder(c, holder_name))
info['dominant_style'][holder_name] = has_dominant_style
info['year_list_style'][holder_name] = has_year_list_style
info['without_c_style'][holder_name] = has_without_c_style
if has_dominant_style or has_year_list_style or has_without_c_style:
info['classified_copyrights'] = info['classified_copyrights'] + 1
return info
################################################################################
# report execution
################################################################################
SEPARATOR = '-'.join(['' for _ in range(80)])
def print_filenames(filenames, verbose):
if not verbose:
return
for filename in filenames:
print("\t%s" % filename)
def print_report(file_infos, verbose):
print(SEPARATOR)
examined = [i['filename'] for i in file_infos]
print("%d files examined according to INCLUDE and EXCLUDE fnmatch rules" %
len(examined))
print_filenames(examined, verbose)
print(SEPARATOR)
print('')
zero_copyrights = [i['filename'] for i in file_infos if
i['all_copyrights'] == 0]
print("%4d with zero copyrights" % len(zero_copyrights))
print_filenames(zero_copyrights, verbose)
one_copyright = [i['filename'] for i in file_infos if
i['all_copyrights'] == 1]
print("%4d with one copyright" % len(one_copyright))
print_filenames(one_copyright, verbose)
two_copyrights = [i['filename'] for i in file_infos if
i['all_copyrights'] == 2]
print("%4d with two copyrights" % len(two_copyrights))
print_filenames(two_copyrights, verbose)
three_copyrights = [i['filename'] for i in file_infos if
i['all_copyrights'] == 3]
print("%4d with three copyrights" % len(three_copyrights))
print_filenames(three_copyrights, verbose)
four_or_more_copyrights = [i['filename'] for i in file_infos if
i['all_copyrights'] >= 4]
print("%4d with four or more copyrights" % len(four_or_more_copyrights))
print_filenames(four_or_more_copyrights, verbose)
print('')
print(SEPARATOR)
print('Copyrights with dominant style:\ne.g. "Copyright (c)" and '
'"<year>" or "<startYear>-<endYear>":\n')
for holder_name in EXPECTED_HOLDER_NAMES:
dominant_style = [i['filename'] for i in file_infos if
i['dominant_style'][holder_name]]
if len(dominant_style) > 0:
print("%4d with '%s'" % (len(dominant_style),
holder_name.replace('\n', '\\n')))
print_filenames(dominant_style, verbose)
print('')
print(SEPARATOR)
print('Copyrights with year list style:\ne.g. "Copyright (c)" and '
'"<year1>, <year2>, ...":\n')
for holder_name in EXPECTED_HOLDER_NAMES:
year_list_style = [i['filename'] for i in file_infos if
i['year_list_style'][holder_name]]
if len(year_list_style) > 0:
print("%4d with '%s'" % (len(year_list_style),
holder_name.replace('\n', '\\n')))
print_filenames(year_list_style, verbose)
print('')
print(SEPARATOR)
print('Copyrights with no "(c)" style:\ne.g. "Copyright" and "<year>" or '
'"<startYear>-<endYear>":\n')
for holder_name in EXPECTED_HOLDER_NAMES:
without_c_style = [i['filename'] for i in file_infos if
i['without_c_style'][holder_name]]
if len(without_c_style) > 0:
print("%4d with '%s'" % (len(without_c_style),
holder_name.replace('\n', '\\n')))
print_filenames(without_c_style, verbose)
print('')
print(SEPARATOR)
unclassified_copyrights = [i['filename'] for i in file_infos if
i['classified_copyrights'] < i['all_copyrights']]
print("%d with unexpected copyright holder names" %
len(unclassified_copyrights))
print_filenames(unclassified_copyrights, verbose)
print(SEPARATOR)
def exec_report(base_directory, verbose):
filenames = get_filenames_to_examine(base_directory)
file_infos = [gather_file_info(f) for f in filenames]
print_report(file_infos, verbose)
################################################################################
# report cmd
################################################################################
REPORT_USAGE = """
Produces a report of all copyright header notices found inside the source files
of a repository.
Usage:
$ ./copyright_header.py report <base_directory> [verbose]
Arguments:
<base_directory> - The base directory of a bitcoin source code repository.
[verbose] - Includes a list of every file of each subcategory in the report.
"""
def report_cmd(argv):
if len(argv) == 2:
sys.exit(REPORT_USAGE)
base_directory = argv[2]
if not os.path.exists(base_directory):
sys.exit("*** bad <base_directory>: %s" % base_directory)
if len(argv) == 3:
verbose = False
elif argv[3] == 'verbose':
verbose = True
else:
sys.exit("*** unknown argument: %s" % argv[2])
exec_report(base_directory, verbose)
################################################################################
# query git for year of last change
################################################################################
GIT_LOG_CMD = "git log --pretty=format:%%ai %s"
def call_git_log(filename):
out = subprocess.check_output((GIT_LOG_CMD % filename).split(' '))
return out.decode("utf-8").split('\n')
def get_git_change_years(filename):
git_log_lines = call_git_log(filename)
if len(git_log_lines) == 0:
return [datetime.date.today().year]
# timestamp is in ISO 8601 format. e.g. "2016-09-05 14:25:32 -0600"
return [line.split(' ')[0].split('-')[0] for line in git_log_lines]
def get_most_recent_git_change_year(filename):
return max(get_git_change_years(filename))
################################################################################
# read and write to file
################################################################################
def read_file_lines(filename):
f = open(filename, 'r', encoding="utf8")
file_lines = f.readlines()
f.close()
return file_lines
def write_file_lines(filename, file_lines):
f = open(filename, 'w', encoding="utf8")
f.write(''.join(file_lines))
f.close()
################################################################################
# update header years execution
################################################################################
COPYRIGHT = 'Copyright \(c\)'
YEAR = "20[0-9][0-9]"
YEAR_RANGE = '(%s)(-%s)?' % (YEAR, YEAR)
HOLDER = 'The Agrarian developers'
UPDATEABLE_LINE_COMPILED = re.compile(' '.join([COPYRIGHT, YEAR_RANGE, HOLDER]))
def get_updatable_copyright_line(file_lines):
index = 0
for line in file_lines:
if UPDATEABLE_LINE_COMPILED.search(line) is not None:
return index, line
index = index + 1
return None, None
def parse_year_range(year_range):
year_split = year_range.split('-')
start_year = year_split[0]
if len(year_split) == 1:
return start_year, start_year
return start_year, year_split[1]
def year_range_to_str(start_year, end_year):
if start_year == end_year:
return start_year
return "%s-%s" % (start_year, end_year)
def create_updated_copyright_line(line, last_git_change_year):
copyright_splitter = 'Copyright (c) '
copyright_split = line.split(copyright_splitter)
# Preserve characters on line that are ahead of the start of the copyright
# notice - they are part of the comment block and vary from file-to-file.
before_copyright = copyright_split[0]
after_copyright = copyright_split[1]
space_split = after_copyright.split(' ')
year_range = space_split[0]
start_year, end_year = parse_year_range(year_range)
if end_year == last_git_change_year:
return line
return (before_copyright + copyright_splitter +
year_range_to_str(start_year, last_git_change_year) + ' ' +
' '.join(space_split[1:]))
def update_updatable_copyright(filename):
file_lines = read_file_lines(filename)
index, line = get_updatable_copyright_line(file_lines)
if not line:
print_file_action_message(filename, "No updatable copyright.")
return
last_git_change_year = get_most_recent_git_change_year(filename)
new_line = create_updated_copyright_line(line, last_git_change_year)
if line == new_line:
print_file_action_message(filename, "Copyright up-to-date.")
return
file_lines[index] = new_line
write_file_lines(filename, file_lines)
print_file_action_message(filename,
"Copyright updated! -> %s" % last_git_change_year)
def exec_update_header_year(base_directory):
for filename in get_filenames_to_examine(base_directory):
update_updatable_copyright(filename)
################################################################################
# update cmd
################################################################################
UPDATE_USAGE = """
Updates all the copyright headers of "The PIVX developers" which were
changed in a year more recent than is listed. For example:
// Copyright (c) <firstYear>-<lastYear> The PIVX developers
will be updated to:
// Copyright (c) <firstYear>-<lastModifiedYear> The PIVX developers
where <lastModifiedYear> is obtained from the 'git log' history.
This subcommand also handles copyright headers that have only a single year. In those cases:
// Copyright (c) <year> The PIVX developers
will be updated to:
// Copyright (c) <year>-<lastModifiedYear> The PIVX developers
where the update is appropriate.
Usage:
$ ./copyright_header.py update <base_directory>
Arguments:
<base_directory> - The base directory of a agrarian source code repository.
"""
def print_file_action_message(filename, action):
print("%-52s %s" % (filename, action))
def update_cmd(argv):
if len(argv) != 3:
sys.exit(UPDATE_USAGE)
base_directory = argv[2]
if not os.path.exists(base_directory):
sys.exit("*** bad base_directory: %s" % base_directory)
exec_update_header_year(base_directory)
################################################################################
# inserted copyright header format
################################################################################
def get_header_lines(header, start_year, end_year):
lines = header.split('\n')[1:-1]
lines[0] = lines[0] % year_range_to_str(start_year, end_year)
return [line + '\n' for line in lines]
CPP_HEADER = '''
// Copyright (c) %s The PIVX developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
def get_cpp_header_lines_to_insert(start_year, end_year):
return reversed(get_header_lines(CPP_HEADER, start_year, end_year))
PYTHON_HEADER = '''
# Copyright (c) %s The PIVX developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
def get_python_header_lines_to_insert(start_year, end_year):
return reversed(get_header_lines(PYTHON_HEADER, start_year, end_year))
################################################################################
# query git for year of last change
################################################################################
def get_git_change_year_range(filename):
years = get_git_change_years(filename)
return min(years), max(years)
################################################################################
# check for existing core copyright
################################################################################
def file_already_has_core_copyright(file_lines):
index, _ = get_updatable_copyright_line(file_lines)
return index is not None
################################################################################
# insert header execution
################################################################################
def file_has_hashbang(file_lines):
if len(file_lines) < 1:
return False
if len(file_lines[0]) <= 2:
return False
return file_lines[0][:2] == '#!'
def insert_python_header(filename, file_lines, start_year, end_year):
if file_has_hashbang(file_lines):
insert_idx = 1
else:
insert_idx = 0
header_lines = get_python_header_lines_to_insert(start_year, end_year)
for line in header_lines:
file_lines.insert(insert_idx, line)
write_file_lines(filename, file_lines)
def insert_cpp_header(filename, file_lines, start_year, end_year):
header_lines = get_cpp_header_lines_to_insert(start_year, end_year)
for line in header_lines:
file_lines.insert(0, line)
write_file_lines(filename, file_lines)
def exec_insert_header(filename, style):
file_lines = read_file_lines(filename)
if file_already_has_core_copyright(file_lines):
sys.exit('*** %s already has a copyright by The PIVX developers'
% (filename))
start_year, end_year = get_git_change_year_range(filename)
if style == 'python':
insert_python_header(filename, file_lines, start_year, end_year)
else:
insert_cpp_header(filename, file_lines, start_year, end_year)
################################################################################
# insert cmd
################################################################################
INSERT_USAGE = """
Inserts a copyright header for "The PIVX developers" at the top of the
file in either Python or C++ style as determined by the file extension. If the
file is a Python file and it has a '#!' starting the first line, the header is
inserted in the line below it.
The copyright dates will be set to be:
"<year_introduced>-<current_year>"
where <year_introduced> is according to the 'git log' history. If
<year_introduced> is equal to <current_year>, the date will be set to be:
"<current_year>"
If the file already has a copyright for "The PIVX developers", the
script will exit.
Usage:
$ ./copyright_header.py insert <file>
Arguments:
<file> - A source file in the bitcoin repository.
"""
def insert_cmd(argv):
if len(argv) != 3:
sys.exit(INSERT_USAGE)
filename = argv[2]
if not os.path.isfile(filename):
sys.exit("*** bad filename: %s" % filename)
_, extension = os.path.splitext(filename)
if extension not in ['.h', '.cpp', '.cc', '.c', '.py']:
sys.exit("*** cannot insert for file extension %s" % extension)
if extension == '.py':
style = 'python'
else:
style = 'cpp'
exec_insert_header(filename, style)
################################################################################
# UI
################################################################################
USAGE = """
copyright_header.py - utilities for managing copyright headers of 'The Bitcoin
Core developers' in repository source files.
Usage:
$ ./copyright_header <subcommand>
Subcommands:
report
update
insert
To see subcommand usage, run them without arguments.
"""
SUBCOMMANDS = ['report', 'update', 'insert']
if __name__ == "__main__":
if len(sys.argv) == 1:
sys.exit(USAGE)
subcommand = sys.argv[1]
if subcommand not in SUBCOMMANDS:
sys.exit(USAGE)
if subcommand == 'report':
report_cmd(sys.argv)
elif subcommand == 'update':
update_cmd(sys.argv)
elif subcommand == 'insert':
insert_cmd(sys.argv)
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env bash
export LC_ALL=C
TOPDIR=${TOPDIR:-$(git rev-parse --show-toplevel)}
BUILDDIR=${BUILDDIR:-$TOPDIR}
BINDIR=${BINDIR:-$BUILDDIR/src}
MANDIR=${MANDIR:-$TOPDIR/doc/man}
BITCOIND=${BITCOIND:-$BINDIR/agrariand}
BITCOINCLI=${BITCOINCLI:-$BINDIR/agrarian-cli}
BITCOINTX=${BITCOINTX:-$BINDIR/agrarian-tx}
BITCOINQT=${BITCOINQT:-$BINDIR/qt/agrarian-qt}
[ ! -x $BITCOIND ] && echo "$BITCOIND not found or not executable." && exit 1
# The autodetected version git tag can screw up manpage output a little bit
BTCVER=($($BITCOINCLI --version | head -n1 | awk -F'[ -]' '{ print $6, $7 }'))
# Create a footer file with copyright content.
# This gets autodetected fine for bitcoind if --version-string is not set,
# but has different outcomes for bitcoin-qt and bitcoin-cli.
echo "[COPYRIGHT]" > footer.h2m
$BITCOIND --version | sed -n '1!p' >> footer.h2m
for cmd in $BITCOIND $BITCOINCLI $BITCOINTX $BITCOINQT; do
cmdname="${cmd##*/}"
help2man -N --version-string=${BTCVER[0]} --include=footer.h2m -o ${MANDIR}/${cmdname}.1 ${cmd}
sed -i "s/\\\-${BTCVER[1]}//g" ${MANDIR}/${cmdname}.1
done
rm -f footer.h2m
+95
View File
@@ -0,0 +1,95 @@
#!/bin/sh
# Copyright (c) 2015 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C
DIR="$1"
COMMIT="$2"
if [ -z "$COMMIT" ]; then
COMMIT=HEAD
fi
# Taken from git-subtree (Copyright (C) 2009 Avery Pennarun <apenwarr@gmail.com>)
find_latest_squash()
{
dir="$1"
sq=
main=
sub=
git log --grep="^git-subtree-dir: $dir/*\$" \
--pretty=format:'START %H%n%s%n%n%b%nEND%n' "$COMMIT" |
while read a b _; do
case "$a" in
START) sq="$b" ;;
git-subtree-mainline:) main="$b" ;;
git-subtree-split:) sub="$b" ;;
END)
if [ -n "$sub" ]; then
if [ -n "$main" ]; then
# a rejoin commit?
# Pretend its sub was a squash.
sq="$sub"
fi
echo "$sq" "$sub"
break
fi
sq=
main=
sub=
;;
esac
done
}
# find latest subtree update
latest_squash="$(find_latest_squash "$DIR")"
if [ -z "$latest_squash" ]; then
echo "ERROR: $DIR is not a subtree" >&2
exit 2
fi
set $latest_squash
old=$1
rev=$2
# get the tree in the current commit
tree_actual=$(git ls-tree -d "$COMMIT" "$DIR" | head -n 1)
if [ -z "$tree_actual" ]; then
echo "FAIL: subtree directory $DIR not found in $COMMIT" >&2
exit 1
fi
set $tree_actual
tree_actual_type=$2
tree_actual_tree=$3
echo "$DIR in $COMMIT currently refers to $tree_actual_type $tree_actual_tree"
if [ "d$tree_actual_type" != "dtree" ]; then
echo "FAIL: subtree directory $DIR is not a tree in $COMMIT" >&2
exit 1
fi
# get the tree at the time of the last subtree update
tree_commit=$(git show -s --format="%T" $old)
echo "$DIR in $COMMIT was last updated in commit $old (tree $tree_commit)"
# ... and compare the actual tree with it
if [ "$tree_actual_tree" != "$tree_commit" ]; then
git diff $tree_commit $tree_actual_tree >&2
echo "FAIL: subtree directory was touched without subtree merge" >&2
exit 1
fi
# get the tree in the subtree commit referred to
if [ "d$(git cat-file -t $rev 2>/dev/null)" != dcommit ]; then
echo "subtree commit $rev unavailable: cannot compare" >&2
exit
fi
tree_subtree=$(git show -s --format="%T" $rev)
echo "$DIR in $COMMIT was last updated to upstream commit $rev (tree $tree_subtree)"
# ... and compare the actual tree with it
if [ "$tree_actual_tree" != "$tree_subtree" ]; then
echo "FAIL: subtree update commit differs from upstream tree!" >&2
exit 1
fi
echo "GOOD"
+384
View File
@@ -0,0 +1,384 @@
#!/usr/bin/env python3
# Copyright (c) 2016-2017 Bitcoin Core Developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
# This script will locally construct a merge commit for a pull request on a
# github repository, inspect it, sign it and optionally push it.
# The following temporary branches are created/overwritten and deleted:
# * pull/$PULL/base (the current master we're merging onto)
# * pull/$PULL/head (the current state of the remote pull request)
# * pull/$PULL/merge (github's merge)
# * pull/$PULL/local-merge (our merge)
# In case of a clean merge that is accepted by the user, the local branch with
# name $BRANCH is overwritten with the merged result, and optionally pushed.
import os
from sys import stdin,stdout,stderr
import argparse
import hashlib
import subprocess
import sys
import json
import codecs
from urllib.request import Request, urlopen
from urllib.error import HTTPError
# External tools (can be overridden using environment)
GIT = os.getenv('GIT','git')
BASH = os.getenv('BASH','bash')
# OS specific configuration for terminal attributes
ATTR_RESET = ''
ATTR_PR = ''
COMMIT_FORMAT = '%h %s (%an)%d'
if os.name == 'posix': # if posix, assume we can use basic terminal escapes
ATTR_RESET = '\033[0m'
ATTR_PR = '\033[1;36m'
COMMIT_FORMAT = '%C(bold blue)%h%Creset %s %C(cyan)(%an)%Creset%C(green)%d%Creset'
def git_config_get(option, default=None):
'''
Get named configuration option from git repository.
'''
try:
return subprocess.check_output([GIT,'config','--get',option]).rstrip().decode('utf-8')
except subprocess.CalledProcessError:
return default
def get_response(req_url, ghtoken):
req = Request(req_url)
if ghtoken is not None:
req.add_header('Authorization', 'token ' + ghtoken)
return urlopen(req)
def retrieve_json(req_url, ghtoken, use_pagination=False):
'''
Retrieve json from github.
Return None if an error happens.
'''
try:
reader = codecs.getreader('utf-8')
if not use_pagination:
return json.load(reader(get_response(req_url, ghtoken)))
obj = []
page_num = 1
while True:
req_url_page = '{}?page={}'.format(req_url, page_num)
result = get_response(req_url_page, ghtoken)
obj.extend(json.load(reader(result)))
link = result.headers.get('link', None)
if link is not None:
link_next = [l for l in link.split(',') if 'rel="next"' in l]
if len(link_next) > 0:
page_num = int(link_next[0][link_next[0].find("page=")+5:link_next[0].find(">")])
continue
break
return obj
except HTTPError as e:
error_message = e.read()
print('Warning: unable to retrieve pull information from github: %s' % e)
print('Detailed error: %s' % error_message)
return None
except Exception as e:
print('Warning: unable to retrieve pull information from github: %s' % e)
return None
def retrieve_pr_info(repo,pull,ghtoken):
req_url = "https://api.github.com/repos/"+repo+"/pulls/"+pull
return retrieve_json(req_url,ghtoken)
def retrieve_pr_comments(repo,pull,ghtoken):
req_url = "https://api.github.com/repos/"+repo+"/issues/"+pull+"/comments"
return retrieve_json(req_url,ghtoken,use_pagination=True)
def retrieve_pr_reviews(repo,pull,ghtoken):
req_url = "https://api.github.com/repos/"+repo+"/pulls/"+pull+"/reviews"
return retrieve_json(req_url,ghtoken,use_pagination=True)
def ask_prompt(text):
print(text,end=" ",file=stderr)
stderr.flush()
reply = stdin.readline().rstrip()
print("",file=stderr)
return reply
def get_symlink_files():
files = sorted(subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', 'HEAD']).splitlines())
ret = []
for f in files:
if (int(f.decode('utf-8').split(" ")[0], 8) & 0o170000) == 0o120000:
ret.append(f.decode('utf-8').split("\t")[1])
return ret
def tree_sha512sum(commit='HEAD'):
# request metadata for entire tree, recursively
files = []
blob_by_name = {}
for line in subprocess.check_output([GIT, 'ls-tree', '--full-tree', '-r', commit]).splitlines():
name_sep = line.index(b'\t')
metadata = line[:name_sep].split() # perms, 'blob', blobid
assert(metadata[1] == b'blob')
name = line[name_sep+1:]
files.append(name)
blob_by_name[name] = metadata[2]
files.sort()
# open connection to git-cat-file in batch mode to request data for all blobs
# this is much faster than launching it per file
p = subprocess.Popen([GIT, 'cat-file', '--batch'], stdout=subprocess.PIPE, stdin=subprocess.PIPE)
overall = hashlib.sha512()
for f in files:
blob = blob_by_name[f]
# request blob
p.stdin.write(blob + b'\n')
p.stdin.flush()
# read header: blob, "blob", size
reply = p.stdout.readline().split()
assert(reply[0] == blob and reply[1] == b'blob')
size = int(reply[2])
# hash the blob data
intern = hashlib.sha512()
ptr = 0
while ptr < size:
bs = min(65536, size - ptr)
piece = p.stdout.read(bs)
if len(piece) == bs:
intern.update(piece)
else:
raise IOError('Premature EOF reading git cat-file output')
ptr += bs
dig = intern.hexdigest()
assert(p.stdout.read(1) == b'\n') # ignore LF that follows blob data
# update overall hash with file hash
overall.update(dig.encode("utf-8"))
overall.update(" ".encode("utf-8"))
overall.update(f)
overall.update("\n".encode("utf-8"))
p.stdin.close()
if p.wait():
raise IOError('Non-zero return value executing git cat-file')
return overall.hexdigest()
def get_acks_from_comments(head_commit, comments):
assert len(head_commit) == 6
ack_str ='\n\nACKs for commit {}:\n'.format(head_commit)
for c in comments:
review = [l for l in c['body'].split('\r\n') if 'ACK' in l and head_commit in l]
if review:
ack_str += ' {}:\n'.format(c['user']['login'])
ack_str += ' {}\n'.format(review[0])
return ack_str
def print_merge_details(pull, title, branch, base_branch, head_branch):
print('%s#%s%s %s %sinto %s%s' % (ATTR_RESET+ATTR_PR,pull,ATTR_RESET,title,ATTR_RESET+ATTR_PR,branch,ATTR_RESET))
subprocess.check_call([GIT,'log','--graph','--topo-order','--pretty=format:'+COMMIT_FORMAT,base_branch+'..'+head_branch])
def parse_arguments():
epilog = '''
In addition, you can set the following git configuration variables:
githubmerge.repository (mandatory),
user.signingkey (mandatory),
user.ghtoken (default: none).
githubmerge.host (default: git@github.com),
githubmerge.branch (no default),
githubmerge.testcmd (default: none).
'''
parser = argparse.ArgumentParser(description='Utility to merge, sign and push github pull requests',
epilog=epilog)
parser.add_argument('pull', metavar='PULL', type=int, nargs=1,
help='Pull request ID to merge')
parser.add_argument('branch', metavar='BRANCH', type=str, nargs='?',
default=None, help='Branch to merge against (default: githubmerge.branch setting, or base branch for pull, or \'master\')')
return parser.parse_args()
def main():
# Extract settings from git repo
repo = git_config_get('githubmerge.repository')
host = git_config_get('githubmerge.host','git@github.com')
opt_branch = git_config_get('githubmerge.branch',None)
testcmd = git_config_get('githubmerge.testcmd')
ghtoken = git_config_get('user.ghtoken')
signingkey = git_config_get('user.signingkey')
if repo is None:
print("ERROR: No repository configured. Use this command to set:", file=stderr)
print("git config githubmerge.repository <owner>/<repo>", file=stderr)
sys.exit(1)
if signingkey is None:
print("ERROR: No GPG signing key set. Set one using:",file=stderr)
print("git config --global user.signingkey <key>",file=stderr)
sys.exit(1)
if host.startswith(('https:','http:')):
host_repo = host+"/"+repo+".git"
else:
host_repo = host+":"+repo
# Extract settings from command line
args = parse_arguments()
pull = str(args.pull[0])
# Receive pull information from github
info = retrieve_pr_info(repo,pull,ghtoken)
if info is None:
sys.exit(1)
comments = retrieve_pr_comments(repo,pull,ghtoken) + retrieve_pr_reviews(repo,pull,ghtoken)
if comments is None:
sys.exit(1)
title = info['title'].strip()
body = info['body'].strip()
# precedence order for destination branch argument:
# - command line argument
# - githubmerge.branch setting
# - base branch for pull (as retrieved from github)
# - 'master'
branch = args.branch or opt_branch or info['base']['ref'] or 'master'
# Initialize source branches
head_branch = 'pull/'+pull+'/head'
base_branch = 'pull/'+pull+'/base'
merge_branch = 'pull/'+pull+'/merge'
local_merge_branch = 'pull/'+pull+'/local-merge'
devnull = open(os.devnull, 'w', encoding="utf8")
try:
subprocess.check_call([GIT,'checkout','-q',branch])
except subprocess.CalledProcessError:
print("ERROR: Cannot check out branch %s." % (branch), file=stderr)
sys.exit(3)
try:
subprocess.check_call([GIT,'fetch','-q',host_repo,'+refs/pull/'+pull+'/*:refs/heads/pull/'+pull+'/*',
'+refs/heads/'+branch+':refs/heads/'+base_branch])
except subprocess.CalledProcessError:
print("ERROR: Cannot find pull request #%s or branch %s on %s." % (pull,branch,host_repo), file=stderr)
sys.exit(3)
try:
subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+head_branch], stdout=devnull, stderr=stdout)
except subprocess.CalledProcessError:
print("ERROR: Cannot find head of pull request #%s on %s." % (pull,host_repo), file=stderr)
sys.exit(3)
try:
subprocess.check_call([GIT,'log','-q','-1','refs/heads/'+merge_branch], stdout=devnull, stderr=stdout)
except subprocess.CalledProcessError:
print("ERROR: Cannot find merge of pull request #%s on %s." % (pull,host_repo), file=stderr)
sys.exit(3)
subprocess.check_call([GIT,'checkout','-q',base_branch])
subprocess.call([GIT,'branch','-q','-D',local_merge_branch], stderr=devnull)
subprocess.check_call([GIT,'checkout','-q','-b',local_merge_branch])
try:
# Go up to the repository's root.
toplevel = subprocess.check_output([GIT,'rev-parse','--show-toplevel']).strip()
os.chdir(toplevel)
# Create unsigned merge commit.
if title:
firstline = 'Merge #%s: %s' % (pull,title)
else:
firstline = 'Merge #%s' % (pull,)
message = firstline + '\n\n'
message += subprocess.check_output([GIT,'log','--no-merges','--topo-order','--pretty=format:%h %s (%an)',base_branch+'..'+head_branch]).decode('utf-8')
message += '\n\nPull request description:\n\n ' + body.replace('\n', '\n ') + '\n'
message += get_acks_from_comments(head_commit=subprocess.check_output([GIT,'log','-1','--pretty=format:%H',head_branch]).decode('utf-8')[:6], comments=comments)
try:
subprocess.check_call([GIT,'merge','-q','--commit','--no-edit','--no-ff','--no-gpg-sign','-m',message.encode('utf-8'),head_branch])
except subprocess.CalledProcessError:
print("ERROR: Cannot be merged cleanly.",file=stderr)
subprocess.check_call([GIT,'merge','--abort'])
sys.exit(4)
logmsg = subprocess.check_output([GIT,'log','--pretty=format:%s','-n','1']).decode('utf-8')
if logmsg.rstrip() != firstline.rstrip():
print("ERROR: Creating merge failed (already merged?).",file=stderr)
sys.exit(4)
symlink_files = get_symlink_files()
for f in symlink_files:
print("ERROR: File %s was a symlink" % f)
if len(symlink_files) > 0:
sys.exit(4)
# Put tree SHA512 into the message
try:
first_sha512 = tree_sha512sum()
message += '\n\nTree-SHA512: ' + first_sha512
except subprocess.CalledProcessError:
print("ERROR: Unable to compute tree hash")
sys.exit(4)
try:
subprocess.check_call([GIT,'commit','--amend','--no-gpg-sign','-m',message.encode('utf-8')])
except subprocess.CalledProcessError:
print("ERROR: Cannot update message.", file=stderr)
sys.exit(4)
print_merge_details(pull, title, branch, base_branch, head_branch)
print()
# Run test command if configured.
if testcmd:
if subprocess.call(testcmd,shell=True):
print("ERROR: Running %s failed." % testcmd,file=stderr)
sys.exit(5)
# Show the created merge.
diff = subprocess.check_output([GIT,'diff',merge_branch+'..'+local_merge_branch])
subprocess.check_call([GIT,'diff',base_branch+'..'+local_merge_branch])
if diff:
print("WARNING: merge differs from github!",file=stderr)
reply = ask_prompt("Type 'ignore' to continue.")
if reply.lower() == 'ignore':
print("Difference with github ignored.",file=stderr)
else:
sys.exit(6)
else:
# Verify the result manually.
print("Dropping you on a shell so you can try building/testing the merged source.",file=stderr)
print("Run 'git diff HEAD~' to show the changes being merged.",file=stderr)
print("Type 'exit' when done.",file=stderr)
if os.path.isfile('/etc/debian_version'): # Show pull number on Debian default prompt
os.putenv('debian_chroot',pull)
subprocess.call([BASH,'-i'])
second_sha512 = tree_sha512sum()
if first_sha512 != second_sha512:
print("ERROR: Tree hash changed unexpectedly",file=stderr)
sys.exit(8)
# Sign the merge commit.
print_merge_details(pull, title, branch, base_branch, head_branch)
while True:
reply = ask_prompt("Type 's' to sign off on the above merge, or 'x' to reject and exit.").lower()
if reply == 's':
try:
subprocess.check_call([GIT,'commit','-q','--gpg-sign','--amend','--no-edit'])
break
except subprocess.CalledProcessError:
print("Error while signing, asking again.",file=stderr)
elif reply == 'x':
print("Not signing off on merge, exiting.",file=stderr)
sys.exit(1)
# Put the result in branch.
subprocess.check_call([GIT,'checkout','-q',branch])
subprocess.check_call([GIT,'reset','-q','--hard',local_merge_branch])
finally:
# Clean up temporary branches.
subprocess.call([GIT,'checkout','-q',branch])
subprocess.call([GIT,'branch','-q','-D',head_branch],stderr=devnull)
subprocess.call([GIT,'branch','-q','-D',base_branch],stderr=devnull)
subprocess.call([GIT,'branch','-q','-D',merge_branch],stderr=devnull)
subprocess.call([GIT,'branch','-q','-D',local_merge_branch],stderr=devnull)
# Push the result.
while True:
reply = ask_prompt("Type 'push' to push the result to %s, branch %s, or 'x' to exit without pushing." % (host_repo,branch)).lower()
if reply == 'push':
subprocess.check_call([GIT,'push',host_repo,'refs/heads/'+branch])
break
elif reply == 'x':
sys.exit(1)
if __name__ == '__main__':
main()
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/env bash
#
# Copyright (c) 2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
# Check for new lines in diff that introduce trailing whitespace.
# We can't run this check unless we know the commit range for the PR.
export LC_ALL=C
while getopts "?" opt; do
case $opt in
?)
echo "Usage: .lint-whitespace.sh [N]"
echo " TRAVIS_COMMIT_RANGE='<commit range>' .lint-whitespace.sh"
echo " .lint-whitespace.sh -?"
echo "Checks unstaged changes, the previous N commits, or a commit range."
echo "TRAVIS_COMMIT_RANGE='47ba2c3...ee50c9e' .lint-whitespace.sh"
exit 0
;;
esac
done
if [ -z "${TRAVIS_COMMIT_RANGE}" ]; then
if [ "$1" ]; then
TRAVIS_COMMIT_RANGE="HEAD~$1...HEAD"
else
TRAVIS_COMMIT_RANGE="HEAD"
fi
fi
showdiff() {
if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- "." ":(exclude)depends/patches/" ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/"; then
echo "Failed to get a diff"
exit 1
fi
}
showcodediff() {
if ! git diff -U0 "${TRAVIS_COMMIT_RANGE}" -- *.cpp *.h *.md *.py *.sh ":(exclude)src/leveldb/" ":(exclude)src/secp256k1/" ":(exclude)src/univalue/" ":(exclude)doc/release-notes/"; then
echo "Failed to get a diff"
exit 1
fi
}
RET=0
# Check if trailing whitespace was found in the diff.
if showdiff | grep -E -q '^\+.*\s+$'; then
echo "This diff appears to have added new lines with trailing whitespace."
echo "The following changes were suspected:"
FILENAME=""
SEEN=0
SEENLN=0
while read -r line; do
if [[ "$line" =~ ^diff ]]; then
FILENAME="$line"
SEEN=0
elif [[ "$line" =~ ^@@ ]]; then
LINENUMBER="$line"
SEENLN=0
else
if [ "$SEEN" -eq 0 ]; then
# The first time a file is seen with trailing whitespace, we print the
# filename (preceded by a newline).
echo
echo "$FILENAME"
SEEN=1
fi
if [ "$SEENLN" -eq 0 ]; then
echo "$LINENUMBER"
SEENLN=1
fi
echo "$line"
fi
done < <(showdiff | grep -E '^(diff --git |@@|\+.*\s+$)')
RET=1
fi
# Check if tab characters were found in the diff.
if showcodediff | perl -nle '$MATCH++ if m{^\+.*\t}; END{exit 1 unless $MATCH>0}' > /dev/null; then
echo "This diff appears to have added new lines with tab characters instead of spaces."
echo "The following changes were suspected:"
FILENAME=""
SEEN=0
SEENLN=0
while read -r line; do
if [[ "$line" =~ ^diff ]]; then
FILENAME="$line"
SEEN=0
elif [[ "$line" =~ ^@@ ]]; then
LINENUMBER="$line"
SEENLN=0
else
if [ "$SEEN" -eq 0 ]; then
# The first time a file is seen with a tab character, we print the
# filename (preceded by a newline).
echo
echo "$FILENAME"
SEEN=1
fi
if [ "$SEENLN" -eq 0 ]; then
echo "$LINENUMBER"
SEENLN=1
fi
echo "$line"
fi
done < <(showcodediff | perl -nle 'print if m{^(diff --git |@@|\+.*\t)}')
RET=1
fi
exit $RET
+102
View File
@@ -0,0 +1,102 @@
#!/usr/bin/env python3
# Copyright (c) 2017-2018 The PIVX developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import os, sys
from subprocess import check_output
def countRelevantCommas(line):
openParensPosStack = []
openParensPos = 0
charCounter = 0
numRelevantCommas = 0
firstOpenParensIndex = line.find("(")
for char in line:
if char == '(':
openParensPosStack.append(charCounter)
if char == ')':
openParensPosStack.pop()
if char == "," and openParensPosStack[-1] == firstOpenParensIndex:
numRelevantCommas += 1
charCounter += 1
return numRelevantCommas
if __name__ == "__main__":
out = check_output("git rev-parse --show-toplevel", shell=True, universal_newlines=True)
srcDir = out.rstrip() + "/src/"
filelist = [os.path.join(dp, f) for dp, dn, filenames in os.walk(srcDir) for f in filenames if os.path.splitext(f)[1] == '.cpp' or os.path.splitext(f)[1] == '.h' ]
incorrectInstanceCounter = 0
for file in filelist:
f = open(file,"r", encoding="utf-8")
data = f.read()
rows = data.split("\n")
count = 0
full_data = []
lineCounter = 1
tempLine = ""
tempCount = 0
for row in rows:
# Collapse multiple lines into one
tempLine += row
# Line contains LogPrint or LogPrintf
if tempLine.find("LogPrint") != -1:
if tempLine.count("(") == tempLine.count(")"):
havePercents = tempLine.count('%') > 0
if havePercents:
# This line of code has a format specifier that requires checking number of associated arguments
# Determine the number of arguments provided, see if that matches the number of format specifiers
# Count the number of commas after the format specifier string. Check to see if it matches the number of format specifiers.
# Assumes quotes are not escaped in the specifier string and there are no percent signs when specifying the debug level.
# First, determine the position of the comma after the format specifier section, named commaAfterEndSpecifierStringIndex
firstSpecifierIndex = tempLine.find('%')
startSpecifierStringIndex = tempLine.rfind('"',firstSpecifierIndex)
endSpecifierStringIndex = tempLine.find('"',firstSpecifierIndex)
commaAfterEndSpecifierStringIndex = tempLine.find(',',endSpecifierStringIndex)
# Count the number of commas after the specifier string
line = "(" + tempLine[commaAfterEndSpecifierStringIndex:-1]
numCommas = countRelevantCommas(line)
# Determine number of extra percents after specifier string
numExtraPercents = tempLine.count('%', commaAfterEndSpecifierStringIndex)
# Subtract extra from total count. This is the number of expected specifiers
# ignore %%
numPercents = tempLine.count('%') - numExtraPercents - 2*tempLine.count('%%')
if numPercents != numCommas:
print("Incorrect number of arguments for LogPrint(f) statement found.")
print(str(file) + ":" + str(lineCounter - tempCount))
print("Line = " + tempLine)
print("numRelevantCommas = " + str(numCommas) + ", numRelevantPercents = " + str(numPercents))
print("")
incorrectInstanceCounter += 1
# Done with this multiline, clear tempLine
tempLine = ""
tempCount = 0
else:
tempCount += 1
else:
# No LogPrint, clear tempLine
tempLine = ""
tempCount = 0
lineCounter += 1
print("# of incorrect instances: " + str(incorrectInstanceCounter))
sys.exit(incorrectInstanceCounter)
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env python3
# Copyright (c) 2014-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Run this script every time you change one of the png files. Using pngcrush, it will optimize the png files, remove various color profiles, remove ancillary chunks (alla) and text chunks (text).
#pngcrush -brute -ow -rem gAMA -rem cHRM -rem iCCP -rem sRGB -rem alla -rem text
'''
import os
import sys
import subprocess
import hashlib
from PIL import Image # pip3 install Pillow
def file_hash(filename):
'''Return hash of raw file contents'''
with open(filename, 'rb') as f:
return hashlib.sha256(f.read()).hexdigest()
def content_hash(filename):
'''Return hash of RGBA contents of image'''
i = Image.open(filename)
i = i.convert('RGBA')
data = i.tobytes()
return hashlib.sha256(data).hexdigest()
pngcrush = 'pngcrush'
git = 'git'
folders = ["src/qt/res/movies", "src/qt/res/icons", "share/pixmaps"]
basePath = subprocess.check_output([git, 'rev-parse', '--show-toplevel'], universal_newlines=True, encoding='utf8').rstrip('\n')
totalSaveBytes = 0
noHashChange = True
outputArray = []
for folder in folders:
absFolder=os.path.join(basePath, folder)
for file in os.listdir(absFolder):
extension = os.path.splitext(file)[1]
if extension.lower() == '.png':
print("optimizing {}...".format(file), end =' ')
file_path = os.path.join(absFolder, file)
fileMetaMap = {'file' : file, 'osize': os.path.getsize(file_path), 'sha256Old' : file_hash(file_path)}
fileMetaMap['contentHashPre'] = content_hash(file_path)
try:
subprocess.call([pngcrush, "-brute", "-ow", "-rem", "gAMA", "-rem", "cHRM", "-rem", "iCCP", "-rem", "sRGB", "-rem", "alla", "-rem", "text", file_path],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
except:
print("pngcrush is not installed, aborting...")
sys.exit(0)
#verify
if "Not a PNG file" in subprocess.check_output([pngcrush, "-n", "-v", file_path], stderr=subprocess.STDOUT, universal_newlines=True, encoding='utf8'):
print("PNG file "+file+" is corrupted after crushing, check out pngcursh version")
sys.exit(1)
fileMetaMap['sha256New'] = file_hash(file_path)
fileMetaMap['contentHashPost'] = content_hash(file_path)
if fileMetaMap['contentHashPre'] != fileMetaMap['contentHashPost']:
print("Image contents of PNG file {} before and after crushing don't match".format(file))
sys.exit(1)
fileMetaMap['psize'] = os.path.getsize(file_path)
outputArray.append(fileMetaMap)
print("done")
print("summary:\n+++++++++++++++++")
for fileDict in outputArray:
oldHash = fileDict['sha256Old']
newHash = fileDict['sha256New']
totalSaveBytes += fileDict['osize'] - fileDict['psize']
noHashChange = noHashChange and (oldHash == newHash)
print(fileDict['file']+"\n size diff from: "+str(fileDict['osize'])+" to: "+str(fileDict['psize'])+"\n old sha256: "+oldHash+"\n new sha256: "+newHash+"\n")
print("completed. Checksum stable: "+str(noHashChange)+". Total reduction: "+str(totalSaveBytes)+" bytes")
+215
View File
@@ -0,0 +1,215 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2018 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Perform basic ELF security checks on a series of executables.
Exit status will be 0 if successful, and the program will be silent.
Otherwise the exit status will be 1 and it will log which executables failed which checks.
Needs `readelf` (for ELF) and `objdump` (for PE).
'''
import subprocess
import sys
import os
READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
OBJDUMP_CMD = os.getenv('OBJDUMP', '/usr/bin/objdump')
NONFATAL = {} # checks which are non-fatal for now but only generate a warning
def check_ELF_PIE(executable):
'''
Check for position independent executable (PIE), allowing for address space randomization.
'''
p = subprocess.Popen([READELF_CMD, '-h', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Error opening file')
ok = False
for line in stdout.splitlines():
line = line.split()
if len(line)>=2 and line[0] == 'Type:' and line[1] == 'DYN':
ok = True
return ok
def get_ELF_program_headers(executable):
'''Return type and flags for ELF program headers'''
p = subprocess.Popen([READELF_CMD, '-l', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Error opening file')
in_headers = False
count = 0
headers = []
for line in stdout.splitlines():
if line.startswith('Program Headers:'):
in_headers = True
if line == '':
in_headers = False
if in_headers:
if count == 1: # header line
ofs_typ = line.find('Type')
ofs_offset = line.find('Offset')
ofs_flags = line.find('Flg')
ofs_align = line.find('Align')
if ofs_typ == -1 or ofs_offset == -1 or ofs_flags == -1 or ofs_align == -1:
raise ValueError('Cannot parse elfread -lW output')
elif count > 1:
typ = line[ofs_typ:ofs_offset].rstrip()
flags = line[ofs_flags:ofs_align].rstrip()
headers.append((typ, flags))
count += 1
return headers
def check_ELF_NX(executable):
'''
Check that no sections are writable and executable (including the stack)
'''
have_wx = False
have_gnu_stack = False
for (typ, flags) in get_ELF_program_headers(executable):
if typ == 'GNU_STACK':
have_gnu_stack = True
if 'W' in flags and 'E' in flags: # section is both writable and executable
have_wx = True
return have_gnu_stack and not have_wx
def check_ELF_RELRO(executable):
'''
Check for read-only relocations.
GNU_RELRO program header must exist
Dynamic section must have BIND_NOW flag
'''
have_gnu_relro = False
for (typ, flags) in get_ELF_program_headers(executable):
# Note: not checking flags == 'R': here as linkers set the permission differently
# This does not affect security: the permission flags of the GNU_RELRO program header are ignored, the PT_LOAD header determines the effective permissions.
# However, the dynamic linker need to write to this area so these are RW.
# Glibc itself takes care of mprotecting this area R after relocations are finished.
# See also https://marc.info/?l=binutils&m=1498883354122353
if typ == 'GNU_RELRO':
have_gnu_relro = True
have_bindnow = False
p = subprocess.Popen([READELF_CMD, '-d', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Error opening file')
for line in stdout.splitlines():
tokens = line.split()
if len(tokens)>1 and tokens[1] == '(BIND_NOW)' or (len(tokens)>2 and tokens[1] == '(FLAGS)' and 'BIND_NOW' in tokens[2:]):
have_bindnow = True
return have_gnu_relro and have_bindnow
def check_ELF_Canary(executable):
'''
Check for use of stack canary
'''
p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Error opening file')
ok = False
for line in stdout.splitlines():
if '__stack_chk_fail' in line:
ok = True
return ok
def get_PE_dll_characteristics(executable):
'''
Get PE DllCharacteristics bits.
Returns a tuple (arch,bits) where arch is 'i386:x86-64' or 'i386'
and bits is the DllCharacteristics value.
'''
p = subprocess.Popen([OBJDUMP_CMD, '-x', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Error opening file')
arch = ''
bits = 0
for line in stdout.splitlines():
tokens = line.split()
if len(tokens)>=2 and tokens[0] == 'architecture:':
arch = tokens[1].rstrip(',')
if len(tokens)>=2 and tokens[0] == 'DllCharacteristics':
bits = int(tokens[1],16)
return (arch,bits)
IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA = 0x0020
IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = 0x0040
IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = 0x0100
def check_PE_DYNAMIC_BASE(executable):
'''PIE: DllCharacteristics bit 0x40 signifies dynamicbase (ASLR)'''
(arch,bits) = get_PE_dll_characteristics(executable)
reqbits = IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE
return (bits & reqbits) == reqbits
# On 64 bit, must support high-entropy 64-bit address space layout randomization in addition to DYNAMIC_BASE
# to have secure ASLR.
def check_PE_HIGH_ENTROPY_VA(executable):
'''PIE: DllCharacteristics bit 0x20 signifies high-entropy ASLR'''
(arch,bits) = get_PE_dll_characteristics(executable)
if arch == 'i386:x86-64':
reqbits = IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA
else: # Unnecessary on 32-bit
assert(arch == 'i386')
reqbits = 0
return (bits & reqbits) == reqbits
def check_PE_NX(executable):
'''NX: DllCharacteristics bit 0x100 signifies nxcompat (DEP)'''
(arch,bits) = get_PE_dll_characteristics(executable)
return (bits & IMAGE_DLL_CHARACTERISTICS_NX_COMPAT) == IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
CHECKS = {
'ELF': [
('PIE', check_ELF_PIE),
('NX', check_ELF_NX),
('RELRO', check_ELF_RELRO),
('Canary', check_ELF_Canary)
],
'PE': [
('DYNAMIC_BASE', check_PE_DYNAMIC_BASE),
('HIGH_ENTROPY_VA', check_PE_HIGH_ENTROPY_VA),
('NX', check_PE_NX)
]
}
def identify_executable(executable):
with open(filename, 'rb') as f:
magic = f.read(4)
if magic.startswith(b'MZ'):
return 'PE'
elif magic.startswith(b'\x7fELF'):
return 'ELF'
return None
if __name__ == '__main__':
retval = 0
for filename in sys.argv[1:]:
try:
etype = identify_executable(filename)
if etype is None:
print('%s: unknown format' % filename)
retval = 1
continue
failed = []
warning = []
for (name, func) in CHECKS[etype]:
if not func(filename):
if name in NONFATAL:
warning.append(name)
else:
failed.append(name)
if failed:
print('%s: failed %s' % (filename, ' '.join(failed)))
retval = 1
if warning:
print('%s: warning %s' % (filename, ' '.join(warning)))
except IOError:
print('%s: cannot open' % filename)
retval = 1
sys.exit(retval)
+10
View File
@@ -0,0 +1,10 @@
#!/bin/sh
set -e
if [ $# -ne 3 ];
then echo "usage: $0 <input> <stripped-binary> <debug-binary>"
fi
@OBJCOPY@ --enable-deterministic-archives -p --only-keep-debug $1 $3
@OBJCOPY@ --enable-deterministic-archives -p --strip-debug $1 $2
@STRIP@ --enable-deterministic-archives -p -s $2
@OBJCOPY@ --enable-deterministic-archives -p --add-gnu-debuglink=$3 $2
+177
View File
@@ -0,0 +1,177 @@
#!/usr/bin/env python3
# Copyright (c) 2014 Wladimir J. van der Laan
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
A script to check that the (Linux) executables produced by gitian only contain
allowed gcc, glibc and libstdc++ version symbols. This makes sure they are
still compatible with the minimum supported Linux distribution versions.
Example usage:
find ../gitian-builder/build -type f -executable | xargs python3 contrib/devtools/symbol-check.py
'''
import subprocess
import re
import sys
import os
# Debian 6.0.9 (Squeeze) has:
#
# - g++ version 4.4.5 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=g%2B%2B)
# - libc version 2.11.3 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=libc6)
# - libstdc++ version 4.4.5 (https://packages.debian.org/search?suite=default&section=all&arch=any&searchon=names&keywords=libstdc%2B%2B6)
#
# Ubuntu 10.04.4 (Lucid Lynx) has:
#
# - g++ version 4.4.3 (http://packages.ubuntu.com/search?keywords=g%2B%2B&searchon=names&suite=lucid&section=all)
# - libc version 2.11.1 (http://packages.ubuntu.com/search?keywords=libc6&searchon=names&suite=lucid&section=all)
# - libstdc++ version 4.4.3 (http://packages.ubuntu.com/search?suite=lucid&section=all&arch=any&keywords=libstdc%2B%2B&searchon=names)
#
# Taking the minimum of these as our target.
#
# According to GNU ABI document (http://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) this corresponds to:
# GCC 4.4.0: GCC_4.4.0
# GCC 4.4.2: GLIBCXX_3.4.13, CXXABI_1.3.3
# (glibc) GLIBC_2_11
#
MAX_VERSIONS = {
'GCC': (4,4,0),
'CXXABI': (1,3,3),
'GLIBCXX': (3,4,13),
'GLIBC': (2,11),
'LIBATOMIC': (1,0)
}
# See here for a description of _IO_stdin_used:
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=634261#109
# Ignore symbols that are exported as part of every executable
IGNORE_EXPORTS = {
'_edata', '_end', '__end__', '_init', '__bss_start', '__bss_start__', '_bss_end__', '__bss_end__', '_fini', '_IO_stdin_used', 'stdin', 'stdout', 'stderr'
}
READELF_CMD = os.getenv('READELF', '/usr/bin/readelf')
CPPFILT_CMD = os.getenv('CPPFILT', '/usr/bin/c++filt')
# Allowed NEEDED libraries
ALLOWED_LIBRARIES = {
# bitcoind and bitcoin-qt
'libgcc_s.so.1', # GCC base support
'libc.so.6', # C library
'libpthread.so.0', # threading
'libanl.so.1', # DNS resolve
'libm.so.6', # math library
'librt.so.1', # real-time (clock)
'libatomic.so.1',
'ld-linux-x86-64.so.2', # 64-bit dynamic linker
'ld-linux.so.2', # 32-bit dynamic linker
'ld-linux-aarch64.so.1', # 64-bit ARM dynamic linker
'ld-linux-armhf.so.3', # 32-bit ARM dynamic linker
'ld-linux-riscv64-lp64d.so.1', # 64-bit RISC-V dynamic linker
# bitcoin-qt only
'libX11-xcb.so.1', # part of X11
'libX11.so.6', # part of X11
'libxcb.so.1', # part of X11
'libfontconfig.so.1', # font support
'libfreetype.so.6', # font parsing
'libdl.so.2' # programming interface to dynamic linker
}
ARCH_MIN_GLIBC_VER = {
'80386': (2,1),
'X86-64': (2,2,5),
'ARM': (2,4),
'AArch64':(2,17),
'RISC-V': (2,27)
}
class CPPFilt(object):
'''
Demangle C++ symbol names.
Use a pipe to the 'c++filt' command.
'''
def __init__(self):
self.proc = subprocess.Popen(CPPFILT_CMD, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True)
def __call__(self, mangled):
self.proc.stdin.write(mangled + '\n')
self.proc.stdin.flush()
return self.proc.stdout.readline().rstrip()
def close(self):
self.proc.stdin.close()
self.proc.stdout.close()
self.proc.wait()
def read_symbols(executable, imports=True):
'''
Parse an ELF executable and return a list of (symbol,version) tuples
for dynamic, imported symbols.
'''
p = subprocess.Popen([READELF_CMD, '--dyn-syms', '-W', '-h', executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Could not read symbols for %s: %s' % (executable, stderr.strip()))
syms = []
for line in stdout.splitlines():
line = line.split()
if 'Machine:' in line:
arch = line[-1]
if len(line)>7 and re.match('[0-9]+:$', line[0]):
(sym, _, version) = line[7].partition('@')
is_import = line[6] == 'UND'
if version.startswith('@'):
version = version[1:]
if is_import == imports:
syms.append((sym, version, arch))
return syms
def check_version(max_versions, version, arch):
if '_' in version:
(lib, _, ver) = version.rpartition('_')
else:
lib = version
ver = '0'
ver = tuple([int(x) for x in ver.split('.')])
if not lib in max_versions:
return False
return ver <= max_versions[lib] or lib == 'GLIBC' and ver <= ARCH_MIN_GLIBC_VER[arch]
def read_libraries(filename):
p = subprocess.Popen([READELF_CMD, '-d', '-W', filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
if p.returncode:
raise IOError('Error opening file')
libraries = []
for line in stdout.splitlines():
tokens = line.split()
if len(tokens)>2 and tokens[1] == '(NEEDED)':
match = re.match('^Shared library: \[(.*)\]$', ' '.join(tokens[2:]))
if match:
libraries.append(match.group(1))
else:
raise ValueError('Unparseable (NEEDED) specification')
return libraries
if __name__ == '__main__':
cppfilt = CPPFilt()
retval = 0
for filename in sys.argv[1:]:
# Check imported symbols
for sym,version,arch in read_symbols(filename, True):
if version and not check_version(MAX_VERSIONS, version, arch):
print('%s: symbol %s from unsupported version %s' % (filename, cppfilt(sym), version))
retval = 1
# Check exported symbols
if arch != 'RISC-V':
for sym,version,arch in read_symbols(filename, False):
if sym in IGNORE_EXPORTS:
continue
print('%s: export of symbol %s not allowed' % (filename, cppfilt(sym)))
retval = 1
# Check dependency libraries
for library_name in read_libraries(filename):
if library_name not in ALLOWED_LIBRARIES:
print('%s: NEEDED library %s is not allowed' % (filename, library_name))
retval = 1
sys.exit(retval)
+71
View File
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
# Copyright (c) 2015-2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Test script for security-check.py
'''
import subprocess
import unittest
def write_testcode(filename):
with open(filename, 'w', encoding="utf8") as f:
f.write('''
#include <stdio.h>
int main()
{
printf("the quick brown fox jumps over the lazy god\\n");
return 0;
}
''')
def call_security_check(cc, source, executable, options):
subprocess.check_call([cc,source,'-o',executable] + options)
p = subprocess.Popen(['./security-check.py',executable], stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
(stdout, stderr) = p.communicate()
return (p.returncode, stdout.rstrip())
class TestSecurityChecks(unittest.TestCase):
def test_ELF(self):
source = 'test1.c'
executable = 'test1'
cc = 'gcc'
write_testcode(source)
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-zexecstack','-fno-stack-protector','-Wl,-znorelro']),
(1, executable+': failed PIE NX RELRO Canary'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fno-stack-protector','-Wl,-znorelro']),
(1, executable+': failed PIE RELRO Canary'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro']),
(1, executable+': failed PIE RELRO'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-znorelro','-pie','-fPIE']),
(1, executable+': failed RELRO'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,-znoexecstack','-fstack-protector-all','-Wl,-zrelro','-Wl,-z,now','-pie','-fPIE']),
(0, ''))
def test_32bit_PE(self):
source = 'test1.c'
executable = 'test1.exe'
cc = 'i686-w64-mingw32-gcc'
write_testcode(source)
self.assertEqual(call_security_check(cc, source, executable, []),
(1, executable+': failed DYNAMIC_BASE NX'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat']),
(1, executable+': failed DYNAMIC_BASE'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']),
(0, ''))
def test_64bit_PE(self):
source = 'test1.c'
executable = 'test1.exe'
cc = 'x86_64-w64-mingw32-gcc'
write_testcode(source)
self.assertEqual(call_security_check(cc, source, executable, []), (1, executable+': failed DYNAMIC_BASE NX\n'+executable+': warning HIGH_ENTROPY_VA'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat']), (1, executable+': failed DYNAMIC_BASE\n'+executable+': warning HIGH_ENTROPY_VA'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase']), (0, executable+': warning HIGH_ENTROPY_VA'))
self.assertEqual(call_security_check(cc, source, executable, ['-Wl,--nxcompat','-Wl,--dynamicbase','-Wl,--high-entropy-va']), (0, ''))
if __name__ == '__main__':
unittest.main()
+210
View File
@@ -0,0 +1,210 @@
#!/usr/bin/env python3
# Copyright (c) 2014 Wladimir J. van der Laan
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
'''
Run this script from the root of the repository to update all translations from
transifex.
It will do the following automatically:
- fetch all translations using the tx tool
- post-process them into valid and committable format
- remove invalid control characters
- remove location tags (makes diffs less noisy)
TODO:
- auto-add new translations to the build system according to the translation process
'''
import subprocess
import re
import sys
import os
import io
import xml.etree.ElementTree as ET
# Name of transifex tool
TX = 'tx'
# Name of source language file
SOURCE_LANG = 'agrarian_en.ts'
# Directory with locale files
LOCALE_DIR = 'src/qt/locale'
# Minimum number of messages for translation to be considered at all
MIN_NUM_MESSAGES = 10
def check_at_repository_root():
if not os.path.exists('.git'):
print('No .git directory found')
print('Execute this script at the root of the repository', file=sys.stderr)
sys.exit(1)
def fetch_all_translations():
if subprocess.call([TX, 'pull', '-f', '-a']):
print('Error while fetching translations', file=sys.stderr)
sys.exit(1)
def find_format_specifiers(s):
'''Find all format specifiers in a string.'''
pos = 0
specifiers = []
while True:
percent = s.find('%', pos)
if percent < 0:
break
try:
specifiers.append(s[percent+1])
except:
print('Failed to get specifier')
pos = percent+2
return specifiers
def split_format_specifiers(specifiers):
'''Split format specifiers between numeric (Qt) and others (strprintf)'''
numeric = []
other = []
for s in specifiers:
if s in {'1','2','3','4','5','6','7','8','9'}:
numeric.append(s)
else:
other.append(s)
# If both numeric format specifiers and "others" are used, assume we're dealing
# with a Qt-formatted message. In the case of Qt formatting (see https://doc.qt.io/qt-5/qstring.html#arg)
# only numeric formats are replaced at all. This means "(percentage: %1%)" is valid, without needing
# any kind of escaping that would be necessary for strprintf. Without this, this function
# would wrongly detect '%)' as a printf format specifier.
if numeric:
other = []
# numeric (Qt) can be present in any order, others (strprintf) must be in specified order
return set(numeric),other
def sanitize_string(s):
'''Sanitize string for printing'''
return s.replace('\n',' ')
def check_format_specifiers(source, translation, errors, numerus):
source_f = split_format_specifiers(find_format_specifiers(source))
# assert that no source messages contain both Qt and strprintf format specifiers
# if this fails, go change the source as this is hacky and confusing!
assert(not(source_f[0] and source_f[1]))
try:
translation_f = split_format_specifiers(find_format_specifiers(translation))
except IndexError:
errors.append("Parse error in translation for '%s': '%s'" % (sanitize_string(source), sanitize_string(translation)))
return False
else:
if source_f != translation_f:
if numerus and source_f == (set(), ['n']) and translation_f == (set(), []) and translation.find('%') == -1:
# Allow numerus translations to omit %n specifier (usually when it only has one possible value)
return True
errors.append("Mismatch between '%s' and '%s'" % (sanitize_string(source), sanitize_string(translation)))
return False
return True
def all_ts_files(suffix=''):
for filename in os.listdir(LOCALE_DIR):
# process only language files, and do not process source language
if not filename.endswith('.ts'+suffix) or filename == SOURCE_LANG+suffix:
continue
if suffix: # remove provided suffix
filename = filename[0:-len(suffix)]
filepath = os.path.join(LOCALE_DIR, filename)
yield(filename, filepath)
FIX_RE = re.compile(b'[\x00-\x09\x0b\x0c\x0e-\x1f]')
def remove_invalid_characters(s):
'''Remove invalid characters from translation string'''
return FIX_RE.sub(b'', s)
# Override cdata escape function to make our output match Qt's (optional, just for cleaner diffs for
# comparison, disable by default)
_orig_escape_cdata = None
def escape_cdata(text):
text = _orig_escape_cdata(text)
text = text.replace("'", '&apos;')
text = text.replace('"', '&quot;')
return text
def postprocess_translations(reduce_diff_hacks=False):
print('Checking and postprocessing...')
if reduce_diff_hacks:
global _orig_escape_cdata
_orig_escape_cdata = ET._escape_cdata
ET._escape_cdata = escape_cdata
for (filename,filepath) in all_ts_files():
os.rename(filepath, filepath+'.orig')
have_errors = False
for (filename,filepath) in all_ts_files('.orig'):
# pre-fixups to cope with transifex output
parser = ET.XMLParser(encoding='utf-8') # need to override encoding because 'utf8' is not understood only 'utf-8'
with open(filepath + '.orig', 'rb') as f:
data = f.read()
# remove control characters; this must be done over the entire file otherwise the XML parser will fail
data = remove_invalid_characters(data)
tree = ET.parse(io.BytesIO(data), parser=parser)
# iterate over all messages in file
root = tree.getroot()
for context in root.findall('context'):
for message in context.findall('message'):
numerus = message.get('numerus') == 'yes'
source = message.find('source').text
translation_node = message.find('translation')
# pick all numerusforms
if numerus:
translations = [i.text for i in translation_node.findall('numerusform')]
else:
translations = [translation_node.text]
for translation in translations:
if translation is None:
continue
errors = []
valid = check_format_specifiers(source, translation, errors, numerus)
for error in errors:
print('%s: %s' % (filename, error))
if not valid: # set type to unfinished and clear string if invalid
translation_node.clear()
translation_node.set('type', 'unfinished')
have_errors = True
# Remove location tags
for location in message.findall('location'):
message.remove(location)
# Remove entire message if it is an unfinished translation
if translation_node.get('type') == 'unfinished':
context.remove(message)
# check if document is (virtually) empty, and remove it if so
num_messages = 0
for context in root.findall('context'):
for message in context.findall('message'):
num_messages += 1
if num_messages < MIN_NUM_MESSAGES:
print('Removing %s, as it contains only %i messages' % (filepath, num_messages))
continue
# write fixed-up tree
# if diff reduction requested, replace some XML to 'sanitize' to qt formatting
if reduce_diff_hacks:
out = io.BytesIO()
tree.write(out, encoding='utf-8')
out = out.getvalue()
out = out.replace(b' />', b'/>')
with open(filepath, 'wb') as f:
f.write(out)
else:
tree.write(filepath, encoding='utf-8')
return have_errors
if __name__ == '__main__':
check_at_repository_root()
fetch_all_translations()
postprocess_translations()
+25
View File
@@ -0,0 +1,25 @@
#!/usr/bin/env python3
import argparse
parser = argparse.ArgumentParser(description='Remove the coverage data from a tracefile for all files matching the pattern.')
parser.add_argument('--pattern', '-p', action='append', help='the pattern of files to remove', required=True)
parser.add_argument('tracefile', help='the tracefile to remove the coverage data from')
parser.add_argument('outfile', help='filename for the output to be written to')
args = parser.parse_args()
tracefile = args.tracefile
pattern = args.pattern
outfile = args.outfile
in_remove = False
with open(tracefile, 'r', encoding="utf8") as f:
with open(outfile, 'w', encoding="utf8") as wf:
for line in f:
for p in pattern:
if line.startswith("SF:") and p in line:
in_remove = True
if not in_remove:
wf.write(line)
if line == 'end_of_record\n':
in_remove = False
+262
View File
@@ -0,0 +1,262 @@
#!/usr/bin/env python3
import argparse
import os
import subprocess
import sys
def setup():
global args, workdir
programs = ['ruby', 'git', 'make', 'wget', 'curl']
if args.kvm:
programs += ['apt-cacher-ng', 'python-vm-builder', 'qemu-kvm', 'qemu-utils']
elif args.docker and not os.path.isfile('/lib/systemd/system/docker.service'):
dockers = ['docker.io', 'docker-ce']
for i in dockers:
return_code = subprocess.call(['sudo', 'apt-get', 'install', '-qq', i])
if return_code == 0:
break
if return_code != 0:
print('Cannot find any way to install Docker.', file=sys.stderr)
sys.exit(1)
else:
programs += ['apt-cacher-ng', 'lxc', 'debootstrap']
subprocess.check_call(['sudo', 'apt-get', 'install', '-qq'] + programs)
if not os.path.isdir('gitian.sigs'):
subprocess.check_call(['git', 'clone', 'https://github.com/agrarian-Project/gitian.sigs.git'])
if not os.path.isdir('agrarian-detached-sigs'):
subprocess.check_call(['git', 'clone', 'https://github.com/agrarian-Project/agrarian-detached-sigs.git'])
if not os.path.isdir('gitian-builder'):
subprocess.check_call(['git', 'clone', 'https://github.com/devrandom/gitian-builder.git'])
if not os.path.isdir('agrarian'):
subprocess.check_call(['git', 'clone', 'https://github.com/agrarian-Project/agrarian.git'])
os.chdir('gitian-builder')
make_image_prog = ['bin/make-base-vm', '--suite', 'bionic', '--arch', 'amd64']
if args.docker:
make_image_prog += ['--docker']
elif not args.kvm:
make_image_prog += ['--lxc']
subprocess.check_call(make_image_prog)
os.chdir(workdir)
if args.is_bionic and not args.kvm and not args.docker:
subprocess.check_call(['sudo', 'sed', '-i', 's/lxcbr0/br0/', '/etc/default/lxc-net'])
print('Reboot is required')
sys.exit(0)
def build():
global args, workdir
os.makedirs('agrarian-binaries/' + args.version, exist_ok=True)
print('\nBuilding Dependencies\n')
os.chdir('gitian-builder')
os.makedirs('inputs', exist_ok=True)
subprocess.check_call(['wget', '-N', '-P', 'inputs', 'https://downloads.sourceforge.net/project/osslsigncode/osslsigncode/osslsigncode-1.7.1.tar.gz'])
subprocess.check_call(['wget', '-N', '-P', 'inputs', 'https://bitcoincore.org/cfields/osslsigncode-Backports-to-1.7.1.patch'])
subprocess.check_call(["echo 'a8c4e9cafba922f89de0df1f2152e7be286aba73f78505169bc351a7938dd911 inputs/osslsigncode-Backports-to-1.7.1.patch' | sha256sum -c"], shell=True)
subprocess.check_call(["echo 'f9a8cdb38b9c309326764ebc937cba1523a3a751a7ab05df3ecc99d18ae466c9 inputs/osslsigncode-1.7.1.tar.gz' | sha256sum -c"], shell=True)
subprocess.check_call(['make', '-C', '../agrarian/depends', 'download', 'SOURCES_PATH=' + os.getcwd() + '/cache/common'])
if args.linux:
print('\nCompiling ' + args.version + ' Linux')
subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'agrarian='+args.commit, '--url', 'agrarian='+args.url, '../agrarian/contrib/gitian-descriptors/gitian-linux.yml'])
subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-linux', '--destination', '../gitian.sigs/', '../agrarian/contrib/gitian-descriptors/gitian-linux.yml'])
subprocess.check_call('mv build/out/agrarian-*.tar.gz build/out/src/agrarian-*.tar.gz ../agrarian-binaries/'+args.version, shell=True)
if args.windows:
print('\nCompiling ' + args.version + ' Windows')
subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'agrarian='+args.commit, '--url', 'agrarian='+args.url, '../agrarian/contrib/gitian-descriptors/gitian-win.yml'])
subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-unsigned', '--destination', '../gitian.sigs/', '../agrarian/contrib/gitian-descriptors/gitian-win.yml'])
subprocess.check_call('mv build/out/agrarian-*-win-unsigned.tar.gz inputs/', shell=True)
subprocess.check_call('mv build/out/agrarian-*.zip build/out/agrarian-*.exe build/out/src/agrarian-*.tar.gz ../agrarian-binaries/'+args.version, shell=True)
if args.macos:
print('\nCompiling ' + args.version + ' MacOS')
subprocess.check_call(['bin/gbuild', '-j', args.jobs, '-m', args.memory, '--commit', 'agrarian='+args.commit, '--url', 'agrarian='+args.url, '../agrarian/contrib/gitian-descriptors/gitian-osx.yml'])
subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-unsigned', '--destination', '../gitian.sigs/', '../agrarian/contrib/gitian-descriptors/gitian-osx.yml'])
subprocess.check_call('mv build/out/agrarian-*-osx-unsigned.tar.gz inputs/', shell=True)
subprocess.check_call('mv build/out/agrarian-*.tar.gz build/out/agrarian-*.dmg build/out/src/agrarian-*.tar.gz ../agrarian-binaries/'+args.version, shell=True)
os.chdir(workdir)
if args.commit_files:
print('\nCommitting '+args.version+' Unsigned Sigs\n')
os.chdir('gitian.sigs')
subprocess.check_call(['git', 'add', args.version+'-linux/'+args.signer])
subprocess.check_call(['git', 'add', args.version+'-win-unsigned/'+args.signer])
subprocess.check_call(['git', 'add', args.version+'-osx-unsigned/'+args.signer])
subprocess.check_call(['git', 'commit', '-m', 'Add '+args.version+' unsigned sigs for '+args.signer])
os.chdir(workdir)
def sign():
global args, workdir
os.chdir('gitian-builder')
if args.windows:
print('\nSigning ' + args.version + ' Windows')
subprocess.check_call('cp inputs/agrarian-' + args.version + '-win-unsigned.tar.gz inputs/agrarian-win-unsigned.tar.gz', shell=True)
subprocess.check_call(['bin/gbuild', '--skip-image', '--upgrade', '--commit', 'signature='+args.commit, '../agrarian/contrib/gitian-descriptors/gitian-win-signer.yml'])
subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-win-signed', '--destination', '../gitian.sigs/', '../agrarian/contrib/gitian-descriptors/gitian-win-signer.yml'])
subprocess.check_call('mv build/out/agrarian-*win64-setup.exe ../agrarian-binaries/'+args.version, shell=True)
subprocess.check_call('mv build/out/agrarian-*win32-setup.exe ../agrarian-binaries/'+args.version, shell=True)
if args.macos:
print('\nSigning ' + args.version + ' MacOS')
subprocess.check_call('cp inputs/agrarian-' + args.version + '-osx-unsigned.tar.gz inputs/agrarian-osx-unsigned.tar.gz', shell=True)
subprocess.check_call(['bin/gbuild', '--skip-image', '--upgrade', '--commit', 'signature='+args.commit, '../agrarian/contrib/gitian-descriptors/gitian-osx-signer.yml'])
subprocess.check_call(['bin/gsign', '-p', args.sign_prog, '--signer', args.signer, '--release', args.version+'-osx-signed', '--destination', '../gitian.sigs/', '../agrarian/contrib/gitian-descriptors/gitian-osx-signer.yml'])
subprocess.check_call('mv build/out/agrarian-osx-signed.dmg ../agrarian-binaries/'+args.version+'/agrarian-'+args.version+'-osx.dmg', shell=True)
os.chdir(workdir)
if args.commit_files:
print('\nCommitting '+args.version+' Signed Sigs\n')
os.chdir('gitian.sigs')
subprocess.check_call(['git', 'add', args.version+'-win-signed/'+args.signer])
subprocess.check_call(['git', 'add', args.version+'-osx-signed/'+args.signer])
subprocess.check_call(['git', 'commit', '-a', '-m', 'Add '+args.version+' signed binary sigs for '+args.signer])
os.chdir(workdir)
def verify():
global args, workdir
rc = 0
os.chdir('gitian-builder')
print('\nVerifying v'+args.version+' Linux\n')
if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-linux', '../agrarian/contrib/gitian-descriptors/gitian-linux.yml']):
print('Verifying v'+args.version+' Linux FAILED\n')
rc = 1
print('\nVerifying v'+args.version+' Windows\n')
if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-unsigned', '../agrarian/contrib/gitian-descriptors/gitian-win.yml']):
print('Verifying v'+args.version+' Windows FAILED\n')
rc = 1
print('\nVerifying v'+args.version+' MacOS\n')
if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-signed', '../agrarian/contrib/gitian-descriptors/gitian-osx.yml']):
print('Verifying v'+args.version+' MacOS FAILED\n')
rc = 1
print('\nVerifying v'+args.version+' Signed Windows\n')
if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-win-signed', '../agrarian/contrib/gitian-descriptors/gitian-win-signer.yml']):
print('Verifying v'+args.version+' Signed Windows FAILED\n')
rc = 1
print('\nVerifying v'+args.version+' Signed MacOS\n')
if subprocess.call(['bin/gverify', '-v', '-d', '../gitian.sigs/', '-r', args.version+'-osx-signed', '../agrarian/contrib/gitian-descriptors/gitian-osx-signer.yml']):
print('Verifying v'+args.version+' Signed MacOS FAILED\n')
rc = 1
os.chdir(workdir)
return rc
def main():
global args, workdir
parser = argparse.ArgumentParser(description='Script for running full Gitian builds.')
parser.add_argument('-c', '--commit', action='store_true', dest='commit', help='Indicate that the version argument is for a commit or branch')
parser.add_argument('-p', '--pull', action='store_true', dest='pull', help='Indicate that the version argument is the number of a github repository pull request')
parser.add_argument('-u', '--url', dest='url', default='https://github.com/agrarian-Project/agrarian', help='Specify the URL of the repository. Default is %(default)s')
parser.add_argument('-v', '--verify', action='store_true', dest='verify', help='Verify the Gitian build')
parser.add_argument('-b', '--build', action='store_true', dest='build', help='Do a Gitian build')
parser.add_argument('-s', '--sign', action='store_true', dest='sign', help='Make signed binaries for Windows and MacOS')
parser.add_argument('-B', '--buildsign', action='store_true', dest='buildsign', help='Build both signed and unsigned binaries')
parser.add_argument('-o', '--os', dest='os', default='lwm', help='Specify which Operating Systems the build is for. Default is %(default)s. l for Linux, w for Windows, m for MacOS')
parser.add_argument('-j', '--jobs', dest='jobs', default='2', help='Number of processes to use. Default %(default)s')
parser.add_argument('-m', '--memory', dest='memory', default='2000', help='Memory to allocate in MiB. Default %(default)s')
parser.add_argument('-k', '--kvm', action='store_true', dest='kvm', help='Use KVM instead of LXC')
parser.add_argument('-d', '--docker', action='store_true', dest='docker', help='Use Docker instead of LXC')
parser.add_argument('-S', '--setup', action='store_true', dest='setup', help='Set up the Gitian building environment. Only works on Debian-based systems (Ubuntu, Debian)')
parser.add_argument('-D', '--detach-sign', action='store_true', dest='detach_sign', help='Create the assert file for detached signing. Will not commit anything.')
parser.add_argument('-n', '--no-commit', action='store_false', dest='commit_files', help='Do not commit anything to git')
parser.add_argument('signer', nargs='?', help='GPG signer to sign each build assert file')
parser.add_argument('version', nargs='?', help='Version number, commit, or branch to build. If building a commit or branch, the -c option must be specified')
args = parser.parse_args()
workdir = os.getcwd()
args.is_bionic = b'bionic' in subprocess.check_output(['lsb_release', '-cs'])
if args.kvm and args.docker:
raise Exception('Error: cannot have both kvm and docker')
# Ensure no more than one environment variable for gitian-builder (USE_LXC, USE_VBOX, USE_DOCKER) is set as they
# can interfere (e.g., USE_LXC being set shadows USE_DOCKER; for details see gitian-builder/libexec/make-clean-vm).
os.environ['USE_LXC'] = ''
os.environ['USE_VBOX'] = ''
os.environ['USE_DOCKER'] = ''
if args.docker:
os.environ['USE_DOCKER'] = '1'
elif not args.kvm:
os.environ['USE_LXC'] = '1'
if 'GITIAN_HOST_IP' not in os.environ.keys():
os.environ['GITIAN_HOST_IP'] = '10.0.3.1'
if 'LXC_GUEST_IP' not in os.environ.keys():
os.environ['LXC_GUEST_IP'] = '10.0.3.5'
if args.setup:
setup()
if args.buildsign:
args.build = True
args.sign = True
if not args.build and not args.sign and not args.verify:
sys.exit(0)
args.linux = 'l' in args.os
args.windows = 'w' in args.os
args.macos = 'm' in args.os
# Disable for MacOS if no SDK found
if args.macos and not os.path.isfile('gitian-builder/inputs/MacOSX10.11.sdk.tar.gz'):
print('Cannot build for MacOS, SDK does not exist. Will build for other OSes')
args.macos = False
args.sign_prog = 'true' if args.detach_sign else 'gpg --detach-sign'
script_name = os.path.basename(sys.argv[0])
if not args.signer:
print(script_name+': Missing signer')
print('Try '+script_name+' --help for more information')
sys.exit(1)
if not args.version:
print(script_name+': Missing version')
print('Try '+script_name+' --help for more information')
sys.exit(1)
# Add leading 'v' for tags
if args.commit and args.pull:
raise Exception('Cannot have both commit and pull')
args.commit = ('' if args.commit else 'v') + args.version
os.chdir('agrarian')
if args.pull:
subprocess.check_call(['git', 'fetch', args.url, 'refs/pull/'+args.version+'/merge'])
os.chdir('../gitian-builder/inputs/agrarian')
subprocess.check_call(['git', 'fetch', args.url, 'refs/pull/'+args.version+'/merge'])
args.commit = subprocess.check_output(['git', 'show', '-s', '--format=%H', 'FETCH_HEAD'], universal_newlines=True, encoding='utf8').strip()
args.version = 'pull-' + args.version
print(args.commit)
subprocess.check_call(['git', 'fetch'])
subprocess.check_call(['git', 'checkout', args.commit])
os.chdir(workdir)
os.chdir('gitian-builder')
subprocess.check_call(['git', 'pull'])
os.chdir(workdir)
if args.build:
build()
if args.sign:
sign()
if args.verify:
os.chdir('gitian.sigs')
subprocess.check_call(['git', 'pull'])
os.chdir(workdir)
sys.exit(verify())
if __name__ == '__main__':
main()
+193
View File
@@ -0,0 +1,193 @@
---
name: "agrarian-linux-3.3"
enable_cache: true
distro: "ubuntu"
suites:
- "bionic"
architectures:
- "amd64"
packages:
- "curl"
- "g++-aarch64-linux-gnu"
- "g++-8-aarch64-linux-gnu"
- "gcc-8-aarch64-linux-gnu"
- "binutils-aarch64-linux-gnu"
- "g++-arm-linux-gnueabihf"
- "g++-8-arm-linux-gnueabihf"
- "gcc-8-arm-linux-gnueabihf"
- "binutils-arm-linux-gnueabihf"
- "g++-riscv64-linux-gnu"
- "g++-8-riscv64-linux-gnu"
- "gcc-8-riscv64-linux-gnu"
- "binutils-riscv64-linux-gnu"
- "g++-8-multilib"
- "gcc-8-multilib"
- "binutils-gold"
- "git"
- "pkg-config"
- "autoconf"
- "libtool"
- "automake"
- "faketime"
- "bsdmainutils"
- "ca-certificates"
- "python3"
remotes:
- "url": "https://github.com/agrarian-project/agrarian.git"
"dir": "agrarian"
files: []
script: |
set -e -o pipefail
WRAP_DIR=$HOME/wrapped
HOSTS="i686-pc-linux-gnu x86_64-linux-gnu arm-linux-gnueabihf aarch64-linux-gnu riscv64-linux-gnu"
CONFIGFLAGS="--enable-glibc-back-compat --enable-reduce-exports --disable-bench --disable-gui-tests"
FAKETIME_HOST_PROGS="gcc g++"
FAKETIME_PROGS="date ar ranlib nm"
HOST_CFLAGS="-O2 -g"
HOST_CXXFLAGS="-O2 -g"
HOST_LDFLAGS=-static-libstdc++
export QT_RCC_TEST=1
export QT_RCC_SOURCE_DATE_OVERRIDE=1
export GZIP="-9n"
export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME""
export TZ="UTC"
export BUILD_DIR=`pwd`
mkdir -p ${WRAP_DIR}
if test -n "$GBUILD_CACHE_ENABLED"; then
export SOURCES_PATH=${GBUILD_COMMON_CACHE}
export BASE_CACHE=${GBUILD_PACKAGE_CACHE}
mkdir -p ${BASE_CACHE} ${SOURCES_PATH}
fi
function create_global_faketime_wrappers {
for prog in ${FAKETIME_PROGS}; do
echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog}
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog}
echo "\$REAL \$@" >> $WRAP_DIR/${prog}
chmod +x ${WRAP_DIR}/${prog}
done
}
function create_per-host_faketime_wrappers {
for i in $HOSTS; do
for prog in ${FAKETIME_HOST_PROGS}; do
if which ${i}-${prog}-8
then
echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog}
echo "REAL=\`which -a ${i}-${prog}-8 | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog}
chmod +x ${WRAP_DIR}/${i}-${prog}
fi
done
done
}
# Faketime for depends so intermediate results are comparable
export PATH_orig=${PATH}
create_global_faketime_wrappers "2000-01-01 12:00:00"
create_per-host_faketime_wrappers "2000-01-01 12:00:00"
export PATH=${WRAP_DIR}:${PATH}
EXTRA_INCLUDES_BASE=$WRAP_DIR/extra_includes
mkdir -p $EXTRA_INCLUDES_BASE
# x86 needs /usr/include/i386-linux-gnu/asm pointed to /usr/include/x86_64-linux-gnu/asm,
# but we can't write there. Instead, create a link here and force it to be included in the
# search paths by wrapping gcc/g++.
mkdir -p $EXTRA_INCLUDES_BASE/i686-pc-linux-gnu
rm -f $WRAP_DIR/extra_includes/i686-pc-linux-gnu/asm
ln -s /usr/include/x86_64-linux-gnu/asm $EXTRA_INCLUDES_BASE/i686-pc-linux-gnu/asm
for prog in gcc g++; do
rm -f ${WRAP_DIR}/${prog}
cat << EOF > ${WRAP_DIR}/${prog}
#!/usr/bin/env bash
REAL="`which -a ${prog}-8 | grep -v ${WRAP_DIR}/${prog} | head -1`"
for var in "\$@"
do
if [ "\$var" = "-m32" ]; then
export C_INCLUDE_PATH="$EXTRA_INCLUDES_BASE/i686-pc-linux-gnu"
export CPLUS_INCLUDE_PATH="$EXTRA_INCLUDES_BASE/i686-pc-linux-gnu"
break
fi
done
\$REAL \$@
EOF
chmod +x ${WRAP_DIR}/${prog}
done
cd agrarian
BASEPREFIX=`pwd`/depends
# Build dependencies for each host
for i in $HOSTS; do
EXTRA_INCLUDES="$EXTRA_INCLUDES_BASE/$i"
if [ -d "$EXTRA_INCLUDES" ]; then
export HOST_ID_SALT="$EXTRA_INCLUDES"
fi
make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}"
unset HOST_ID_SALT
done
# Faketime for binaries
export PATH=${PATH_orig}
create_global_faketime_wrappers "${REFERENCE_DATETIME}"
create_per-host_faketime_wrappers "${REFERENCE_DATETIME}"
export PATH=${WRAP_DIR}:${PATH}
# Create the release tarball using (arbitrarily) the first host
./autogen.sh
CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/
make dist
SOURCEDIST=`echo agrarian-*.tar.gz`
DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'`
# Correct tar file order
mkdir -p temp
pushd temp
tar xf ../$SOURCEDIST
find agrarian-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
popd
# Workaround for tarball not building with the bare tag version (prep)
make -C src obj/build.h
ORIGPATH="$PATH"
# Extract the release tarball into a dir for each host and build
for i in ${HOSTS}; do
export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH}
mkdir -p distsrc-${i}
cd distsrc-${i}
INSTALLPATH=`pwd`/installed/${DISTNAME}
mkdir -p ${INSTALLPATH}
tar --strip-components=1 -xf ../$SOURCEDIST
# Workaround for tarball not building with the bare tag version
echo '#!/bin/true' >share/genbuild.sh
mkdir src/obj
cp ../src/obj/build.h src/obj/
CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}" LDFLAGS="${HOST_LDFLAGS}"
make ${MAKEOPTS}
make ${MAKEOPTS} -C src check-security
make ${MAKEOPTS} -C src check-symbols
make install DESTDIR=${INSTALLPATH}
cd installed
find . -name "lib*.la" -delete
find . -name "lib*.a" -delete
rm -rf ${DISTNAME}/lib/pkgconfig
find ${DISTNAME}/bin -type f -executable -print0 | xargs -0 -n1 -I{} ../contrib/devtools/split-debug.sh {} {} {}.dbg
#find ${DISTNAME}/lib -type f -print0 | xargs -0 -n1 -I{} ../contrib/devtools/split-debug.sh {} {} {}.dbg
cp ../doc/README.md ${DISTNAME}/
find ${DISTNAME} -not -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz
find ${DISTNAME} -name "*.dbg" | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}-debug.tar.gz
cd ../../
rm -rf distsrc-${i}
done
mkdir -p $OUTDIR/src
mv $SOURCEDIST $OUTDIR/src
@@ -0,0 +1,40 @@
---
name: "agrarian-dmg-signer"
distro: "ubuntu"
suites:
- "bionic"
architectures:
- "amd64"
packages:
- "faketime"
remotes:
- "url": "https://github.com/agrarian-project/agrarian-detached-sigs.git"
"dir": "signature"
files:
- "agrarian-osx-unsigned.tar.gz"
script: |
set -e -o pipefail
WRAP_DIR=$HOME/wrapped
mkdir -p ${WRAP_DIR}
export PATH=`pwd`:$PATH
FAKETIME_PROGS="dmg genisoimage"
# Create global faketime wrappers
for prog in ${FAKETIME_PROGS}; do
echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog}
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"${REFERENCE_DATETIME}\"" >> ${WRAP_DIR}/${prog}
echo "\$REAL \$@" >> $WRAP_DIR/${prog}
chmod +x ${WRAP_DIR}/${prog}
done
UNSIGNED=agrarian-osx-unsigned.tar.gz
SIGNED=agrarian-osx-signed.dmg
tar -xf ${UNSIGNED}
OSX_VOLNAME="$(cat osx_volname)"
./detached-sig-apply.sh ${UNSIGNED} signature/osx
${WRAP_DIR}/genisoimage -no-cache-inodes -D -l -probe -V "${OSX_VOLNAME}" -no-pad -r -dir-mode 0755 -apple -o uncompressed.dmg signed-app
${WRAP_DIR}/dmg dmg uncompressed.dmg ${OUTDIR}/${SIGNED}
+170
View File
@@ -0,0 +1,170 @@
---
name: "agrarian-osx-3.3"
enable_cache: true
distro: "ubuntu"
suites:
- "bionic"
architectures:
- "amd64"
packages:
- "ca-certificates"
- "curl"
- "g++"
- "git"
- "pkg-config"
- "autoconf"
- "librsvg2-bin"
- "libtiff-tools"
- "libtool"
- "automake"
- "faketime"
- "bsdmainutils"
- "cmake"
- "imagemagick"
- "libcap-dev"
- "libz-dev"
- "libbz2-dev"
- "python3"
- "python3-dev"
- "python3-setuptools"
- "fonts-tuffy"
remotes:
- "url": "https://github.com/agrarian-project/agrarian.git"
"dir": "agrarian"
files:
- "MacOSX10.11.sdk.tar.gz"
script: |
set -e -o pipefail
WRAP_DIR=$HOME/wrapped
HOSTS="x86_64-apple-darwin14"
CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests GENISOIMAGE=$WRAP_DIR/genisoimage"
FAKETIME_HOST_PROGS=""
FAKETIME_PROGS="ar ranlib date dmg genisoimage"
export QT_RCC_TEST=1
export QT_RCC_SOURCE_DATE_OVERRIDE=1
export GZIP="-9n"
export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME""
export TZ="UTC"
export BUILD_DIR=`pwd`
mkdir -p ${WRAP_DIR}
if test -n "$GBUILD_CACHE_ENABLED"; then
export SOURCES_PATH=${GBUILD_COMMON_CACHE}
export BASE_CACHE=${GBUILD_PACKAGE_CACHE}
mkdir -p ${BASE_CACHE} ${SOURCES_PATH}
fi
export ZERO_AR_DATE=1
function create_global_faketime_wrappers {
for prog in ${FAKETIME_PROGS}; do
echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog}
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog}
echo "\$REAL \$@" >> $WRAP_DIR/${prog}
chmod +x ${WRAP_DIR}/${prog}
done
}
function create_per-host_faketime_wrappers {
for i in $HOSTS; do
for prog in ${FAKETIME_HOST_PROGS}; do
echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog}
echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog}
chmod +x ${WRAP_DIR}/${i}-${prog}
done
done
}
# Faketime for depends so intermediate results are comparable
export PATH_orig=${PATH}
create_global_faketime_wrappers "2000-01-01 12:00:00"
create_per-host_faketime_wrappers "2000-01-01 12:00:00"
export PATH=${WRAP_DIR}:${PATH}
cd agrarian
BASEPREFIX=`pwd`/depends
mkdir -p ${BASEPREFIX}/SDKs
tar -C ${BASEPREFIX}/SDKs -xf ${BUILD_DIR}/MacOSX10.11.sdk.tar.gz
# Build dependencies for each host
for i in $HOSTS; do
make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}"
done
# Faketime for binaries
export PATH=${PATH_orig}
create_global_faketime_wrappers "${REFERENCE_DATETIME}"
create_per-host_faketime_wrappers "${REFERENCE_DATETIME}"
export PATH=${WRAP_DIR}:${PATH}
# Create the release tarball using (arbitrarily) the first host
./autogen.sh
CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/
make dist
SOURCEDIST=`echo agrarian-*.tar.gz`
DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'`
# Correct tar file order
mkdir -p temp
pushd temp
tar xf ../$SOURCEDIST
find agrarian-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
popd
# Workaround for tarball not building with the bare tag version (prep)
make -C src obj/build.h
ORIGPATH="$PATH"
# Extract the release tarball into a dir for each host and build
for i in ${HOSTS}; do
export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH}
mkdir -p distsrc-${i}
cd distsrc-${i}
INSTALLPATH=`pwd`/installed/${DISTNAME}
mkdir -p ${INSTALLPATH}
tar --strip-components=1 -xf ../$SOURCEDIST
# Workaround for tarball not building with the bare tag version
echo '#!/bin/true' >share/genbuild.sh
mkdir src/obj
cp ../src/obj/build.h src/obj/
CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS}
make ${MAKEOPTS}
make install-strip DESTDIR=${INSTALLPATH}
make osx_volname
make deploydir
OSX_VOLNAME="$(cat osx_volname)"
mkdir -p unsigned-app-${i}
cp osx_volname unsigned-app-${i}/
cp contrib/macdeploy/detached-sig-apply.sh unsigned-app-${i}
cp contrib/macdeploy/detached-sig-create.sh unsigned-app-${i}
cp ${BASEPREFIX}/${i}/native/bin/dmg ${BASEPREFIX}/${i}/native/bin/genisoimage unsigned-app-${i}
cp ${BASEPREFIX}/${i}/native/bin/${i}-codesign_allocate unsigned-app-${i}/codesign_allocate
cp ${BASEPREFIX}/${i}/native/bin/${i}-pagestuff unsigned-app-${i}/pagestuff
mv dist unsigned-app-${i}
pushd unsigned-app-${i}
find . | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-osx-unsigned.tar.gz
popd
make deploy
${WRAP_DIR}/dmg dmg "${OSX_VOLNAME}.dmg" ${OUTDIR}/${DISTNAME}-osx-unsigned.dmg
cd installed
find . -name "lib*.la" -delete
find . -name "lib*.a" -delete
rm -rf ${DISTNAME}/lib/pkgconfig
find ${DISTNAME} | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-${i}.tar.gz
cd ../../
done
mkdir -p $OUTDIR/src
mv $SOURCEDIST $OUTDIR/src
mv ${OUTDIR}/${DISTNAME}-x86_64-*.tar.gz ${OUTDIR}/${DISTNAME}-osx64.tar.gz
@@ -0,0 +1,42 @@
---
name: "agrarian-win-signer"
distro: "ubuntu"
suites:
- "bionic"
architectures:
- "amd64"
packages:
# Once osslsigncode supports openssl 1.1, we can change this back to libssl-dev
- "libssl1.0-dev"
- "autoconf"
remotes:
- "url": "https://github.com/agrarian-project/agrarian-detached-sigs.git"
"dir": "signature"
files:
- "osslsigncode-1.7.1.tar.gz"
- "osslsigncode-Backports-to-1.7.1.patch"
- "agrarian-win-unsigned.tar.gz"
script: |
set -e -o pipefail
BUILD_DIR=`pwd`
SIGDIR=${BUILD_DIR}/signature/win
UNSIGNED_DIR=${BUILD_DIR}/unsigned
echo "f9a8cdb38b9c309326764ebc937cba1523a3a751a7ab05df3ecc99d18ae466c9 osslsigncode-1.7.1.tar.gz" | sha256sum -c
echo "a8c4e9cafba922f89de0df1f2152e7be286aba73f78505169bc351a7938dd911 osslsigncode-Backports-to-1.7.1.patch" | sha256sum -c
mkdir -p ${UNSIGNED_DIR}
tar -C ${UNSIGNED_DIR} -xf agrarian-win-unsigned.tar.gz
tar xf osslsigncode-1.7.1.tar.gz
cd osslsigncode-1.7.1
patch -p1 < ${BUILD_DIR}/osslsigncode-Backports-to-1.7.1.patch
./configure --without-gsf --without-curl --disable-dependency-tracking
make
find ${UNSIGNED_DIR} -name "*-unsigned.exe" | while read i; do
INFILE="`basename "${i}"`"
OUTFILE="`echo "${INFILE}" | sed s/-unsigned//`"
./osslsigncode attach-signature -in "${i}" -out "${OUTDIR}/${OUTFILE}" -sigin "${SIGDIR}/${INFILE}.pem"
done
+184
View File
@@ -0,0 +1,184 @@
---
name: "agrarian-win-3.3"
enable_cache: true
distro: "ubuntu"
suites:
- "bionic"
architectures:
- "amd64"
packages:
- "curl"
- "g++"
- "git"
- "pkg-config"
- "autoconf"
- "libtool"
- "automake"
- "faketime"
- "bsdmainutils"
- "mingw-w64"
- "g++-mingw-w64"
- "nsis"
- "zip"
- "ca-certificates"
- "python3"
- "rename"
remotes:
- "url": "https://github.com/agrarian-project/agrarian.git"
"dir": "agrarian"
files: []
script: |
set -e -o pipefail
WRAP_DIR=$HOME/wrapped
HOSTS="i686-w64-mingw32 x86_64-w64-mingw32"
CONFIGFLAGS="--enable-reduce-exports --disable-bench --disable-gui-tests"
FAKETIME_HOST_PROGS="ar ranlib nm windres strip objcopy"
FAKETIME_PROGS="date makensis zip"
HOST_CFLAGS="-O2 -g"
HOST_CXXFLAGS="-O2 -g"
export QT_RCC_TEST=1
export QT_RCC_SOURCE_DATE_OVERRIDE=1
export GZIP="-9n"
export TAR_OPTIONS="--mtime="$REFERENCE_DATE\\\ $REFERENCE_TIME""
export TZ="UTC"
export BUILD_DIR=`pwd`
mkdir -p ${WRAP_DIR}
if test -n "$GBUILD_CACHE_ENABLED"; then
export SOURCES_PATH=${GBUILD_COMMON_CACHE}
export BASE_CACHE=${GBUILD_PACKAGE_CACHE}
mkdir -p ${BASE_CACHE} ${SOURCES_PATH}
fi
function create_global_faketime_wrappers {
for prog in ${FAKETIME_PROGS}; do
echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${prog}
echo "REAL=\`which -a ${prog} | grep -v ${WRAP_DIR}/${prog} | head -1\`" >> ${WRAP_DIR}/${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${prog}
echo "\$REAL \$@" >> $WRAP_DIR/${prog}
chmod +x ${WRAP_DIR}/${prog}
done
}
function create_per-host_faketime_wrappers {
for i in $HOSTS; do
for prog in ${FAKETIME_HOST_PROGS}; do
echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog}
echo "REAL=\`which -a ${i}-${prog} | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog}
chmod +x ${WRAP_DIR}/${i}-${prog}
done
done
}
function create_per-host_linker_wrapper {
# This is only needed for trusty, as the mingw linker leaks a few bytes of
# heap, causing non-determinism. See discussion in https://github.com/bitcoin/bitcoin/pull/6900
for i in $HOSTS; do
mkdir -p ${WRAP_DIR}/${i}
for prog in collect2; do
echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}/${prog}
REAL=$(${i}-gcc -print-prog-name=${prog})
echo "export MALLOC_PERTURB_=255" >> ${WRAP_DIR}/${i}/${prog}
echo "${REAL} \$@" >> $WRAP_DIR/${i}/${prog}
chmod +x ${WRAP_DIR}/${i}/${prog}
done
for prog in gcc g++; do
echo '#!/usr/bin/env bash' > ${WRAP_DIR}/${i}-${prog}
echo "REAL=\`which -a ${i}-${prog}-posix | grep -v ${WRAP_DIR}/${i}-${prog} | head -1\`" >> ${WRAP_DIR}/${i}-${prog}
echo 'export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1' >> ${WRAP_DIR}/${i}-${prog}
echo "export FAKETIME=\"$1\"" >> ${WRAP_DIR}/${i}-${prog}
echo "export COMPILER_PATH=${WRAP_DIR}/${i}" >> ${WRAP_DIR}/${i}-${prog}
echo "\$REAL \$@" >> $WRAP_DIR/${i}-${prog}
chmod +x ${WRAP_DIR}/${i}-${prog}
done
done
}
# Faketime for depends so intermediate results are comparable
export PATH_orig=${PATH}
create_global_faketime_wrappers "2000-01-01 12:00:00"
create_per-host_faketime_wrappers "2000-01-01 12:00:00"
create_per-host_linker_wrapper "2000-01-01 12:00:00"
export PATH=${WRAP_DIR}:${PATH}
cd agrarian
BASEPREFIX=`pwd`/depends
# Build dependencies for each host
for i in $HOSTS; do
make ${MAKEOPTS} -C ${BASEPREFIX} HOST="${i}"
done
# Faketime for binaries
export PATH=${PATH_orig}
create_global_faketime_wrappers "${REFERENCE_DATETIME}"
create_per-host_faketime_wrappers "${REFERENCE_DATETIME}"
create_per-host_linker_wrapper "${REFERENCE_DATETIME}"
export PATH=${WRAP_DIR}:${PATH}
# Create the release tarball using (arbitrarily) the first host
./autogen.sh
CONFIG_SITE=${BASEPREFIX}/`echo "${HOSTS}" | awk '{print $1;}'`/share/config.site ./configure --prefix=/
make dist
SOURCEDIST=`echo agrarian-*.tar.gz`
DISTNAME=`echo ${SOURCEDIST} | sed 's/.tar.*//'`
# Correct tar file order
mkdir -p temp
pushd temp
tar xf ../$SOURCEDIST
find agrarian-* | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ../$SOURCEDIST
mkdir -p $OUTDIR/src
cp ../$SOURCEDIST $OUTDIR/src
popd
# Workaround for tarball not building with the bare tag version (prep)
make -C src obj/build.h
ORIGPATH="$PATH"
# Extract the release tarball into a dir for each host and build
for i in ${HOSTS}; do
export PATH=${BASEPREFIX}/${i}/native/bin:${ORIGPATH}
mkdir -p distsrc-${i}
cd distsrc-${i}
INSTALLPATH=`pwd`/installed/${DISTNAME}
mkdir -p ${INSTALLPATH}
tar --strip-components=1 -xf ../$SOURCEDIST
# Workaround for tarball not building with the bare tag version
echo '#!/bin/true' >share/genbuild.sh
mkdir src/obj
cp ../src/obj/build.h src/obj/
CONFIG_SITE=${BASEPREFIX}/${i}/share/config.site ./configure --prefix=/ --disable-ccache --disable-maintainer-mode --disable-dependency-tracking ${CONFIGFLAGS} CFLAGS="${HOST_CFLAGS}" CXXFLAGS="${HOST_CXXFLAGS}"
make ${MAKEOPTS}
make ${MAKEOPTS} -C src check-security
make deploy
make install DESTDIR=${INSTALLPATH}
rename 's/-setup\.exe$/-setup-unsigned.exe/' *-setup.exe
cp -f agrarian-*setup*.exe $OUTDIR/
cd installed
# mv ${DISTNAME}/bin/*.dll ${DISTNAME}/lib/ # temporarily disabled for Zerocoin
# find . -name "lib*.la" -delete # temporarily disabled for Zerocoin
# find . -name "lib*.a" -delete # temporarily disabled for Zerocoin
rm -rf ${DISTNAME}/lib/pkgconfig
find ${DISTNAME}/bin -type f -executable -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \;
# find ${DISTNAME}/lib -type f -exec ${i}-objcopy --only-keep-debug {} {}.dbg \; -exec ${i}-strip -s {} \; -exec ${i}-objcopy --add-gnu-debuglink={}.dbg {} \;
find ${DISTNAME} -not -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}.zip
find ${DISTNAME} -name "*.dbg" -type f | sort | zip -X@ ${OUTDIR}/${DISTNAME}-${i}-debug.zip
cd ../../
rm -rf distsrc-${i}
done
cp -rf contrib/windeploy $BUILD_DIR
cd $BUILD_DIR/windeploy
mkdir unsigned
cp $OUTDIR/agrarian-*setup-unsigned.exe unsigned/
find . | sort | tar --no-recursion --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > ${OUTDIR}/${DISTNAME}-win-unsigned.tar.gz
mv ${OUTDIR}/${DISTNAME}-x86_64-*-debug.zip ${OUTDIR}/${DISTNAME}-win64-debug.zip
mv ${OUTDIR}/${DISTNAME}-i686-*-debug.zip ${OUTDIR}/${DISTNAME}-win32-debug.zip
mv ${OUTDIR}/${DISTNAME}-x86_64-*.zip ${OUTDIR}/${DISTNAME}-win64.zip
mv ${OUTDIR}/${DISTNAME}-i686-*.zip ${OUTDIR}/${DISTNAME}-win32.zip
+52
View File
@@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
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
GvJbpbEarkB5rJwDBkMB
=M/6E
-----END PGP PUBLIC KEY BLOCK-----
+52
View File
@@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
Xv+1YbtNXqh49IoqCQ==
=et/t
-----END PGP PUBLIC KEY BLOCK-----
+388
View File
@@ -0,0 +1,388 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
KDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIy
MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIASgBKAMB
IgACEQEDEQH/xAGiAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgsQAAIBAwMC
BAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJ
ChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3
eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS
09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+gEAAwEBAQEBAQEBAQAAAAAAAAEC
AwQFBgcICQoLEQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgU
QpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVW
V1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqy
s7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAM
AwEAAhEDEQA/APKrhd0SSIc7PX0quwWSLY/3W647Uukfvo3DgkKQBzU9xaGIF4FO
zup7VrUpt+8i4y6MzlsSJPncbOoIPJqxlEURrwPTFPRWmPy8Lnlj1qy0KLAVVR6k
mpUJT+IG0tEQRyxxDCglj1J70v2gCXPIyORVQgmTALAdeDT/AC1bkgn6mtE30JLf
2lcZI/WkFyTyoGBycc57VCkSHnYPxrb8PaXHfairOieRB+9kB746D8f8a1jFzlYR
0Om2v9jaCGZl+0TfvH/2fQfgP51zOoXJmnLHjtW94gvRuIzyfSuRlLORjpW1aVly
LZFpF2ADGe3Ws6crctJu+6x/L0q1GTHExOcYxVAkpKRncnY+lcNS9k0VdbFGSCSO
XY4JY9D61cgt/IXe5/eEd+ij/Gpg3yg5yPWmAebgZITuSOvtUc0paCslqMlyyE8h
QeM1r6fZosaTTwM6nnGOvp+FPsdLEmx5046rH3PvW46YiZcBiR1HauiEFBXYJObF
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
=iS2u
-----END PGP PUBLIC KEY BLOCK-----
+52
View File
@@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
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
8C9XZfWXj3OSfD45FeqISCGE0RSKSzff1yf5
=tKJr
-----END PGP PUBLIC KEY BLOCK-----
+51
View File
@@ -0,0 +1,51 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
V3x+w2zU0DkwqDFpLQ==
=hsIs
-----END PGP PUBLIC KEY BLOCK-----
+52
View File
@@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
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
vNuZAr0oNiINOswkwGDopEInAlADa0pB
=t7OC
-----END PGP PUBLIC KEY BLOCK-----
+30
View File
@@ -0,0 +1,30 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQENBFjnyFoBCADUkI7ML5LHxGTVF7QWnOG6JkrEMch18fo8jTQPyBg4L5zvXqn/
jJpqK4+UhXS0j7yCYNS/vN392vg3+kB2q/FAbjsotN0qxJgG+/7uAJJBpvLCF2kq
GyN/AqjCfAvqm9sjgLq9JUKpQTRKjDbT8BAeMjE9SfwtsP0JwVz82vulcDjdSh6D
igqHm/Vrtg7Wm3bMr2ZoOIyT8xOJ50uECZJNgOJS6o2MAX2qmQK2Md2u/8DHOpF9
xkMHMWPvaiR1Jkp7KJm0TuIMs5NiXrRzpThq+IwCTnHtclMcf5kiBSIe0PmFNyXL
uChL0CVSBlm85qGvOA92TUxH5jVfc4salWf7ABEBAAG0IXByZXNzdGFiIDxwcmVz
c3RhYjEzMzdAZ21haWwuY29tPokBOAQTAQIAIgUCWOfIWgIbAwYLCQgHAwIGFQgC
CQoLBBYCAwECHgECF4AACgkQoBjGWyAqWfDoGQf/aIxZE1b1eeipvDbj0B3tpChy
2LFLZjiTrv5+r2/5cYmTNwPZJx5iHDzvQwQwVN9U3Rh/N2EKRr9etN3H434SiYY0
+RqvLeesTRz+2rXrYM+YKxk4xPuny68j91DpwYbw3le3tjnUyatFS8Wp3u/X7YWy
WGMZGmkx14AidyJ0erpqT4vxQUxjQbg1E1Uml+K5K+moWoKVElk0Tu/r54X2KGdN
5cCrXVV48oxYldmdxAc9gYATfakjltPXdsKo9csYUZ9Uo8SGbAMRxegEov+PQvY7
Cn4pyjWKWTqoY0DBpv4k8rtGa0a5Dsa+i11ybUKgnc40GalUGygX+BKXnxbkqLkB
DQRY58haAQgA72X6LdfMh3UjY37wJZfCNQGG8Tci4DpOftUGGWMBTSIMQC5IHnnU
jOg9NQC11ee4uLhtx2pzXBGKazamPfrapFGtadC3yqguuzuipOxcEKKPy7EO4lXV
j+IGVuBuoj4yVAYTTJHnopMdvhaZLBgpXBfG6PHhIu0QsohiCGsIJdHWDBsRhxTq
JqcBYTsIcRtLMOVF6/tvM/L6WNHC/uzH//XjMtH+muqi45K9CK0yKKgLkK6rgUKh
gmnzz7C9qtJYoWhygsICFTdBw85kl19GBcbzbyANMwghHKYvLcWf7074b/R55hzG
ICWbMZ96SVlaATYD/NUWOhzgKdUYfpPOUwARAQABiQEfBBgBAgAJBQJY58haAhsM
AAoJEKAYxlsgKlnwgOoH/0QMnpp9yaZLgFXMmKDDUSBI32zdx0Ngj3WXQcheAb0H
BhyGnZ8CJA10BOLoN/ZdaCJ9V3VygliNs2w94GFX3FpHljkv+dN1cgknzjYOVWhp
l1weilBlsUrkiJAi731syYNTxHWO2VocYXrEIE0zCpqo6sadcSHd3/1mFynyhZ/2
IjsOIZHwHyhtBri5B3DtjGLZhmC628anbaD3N7dbfFpvYTd1k54y9PYUAWT1rJ3/
PwcLeLmTMe4d60o2Vru6nOWcsXlB9GLbX7RrSSAmAQmBm26P6MhIjnkXTTFmsqxC
D6VEEIBEXg8WzvW8MVRzOy19bi+7mxokKXrbxu3ezKY=
=nuEB
-----END PGP PUBLIC KEY BLOCK-----
@@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
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
6DfrZCHjeQMTceEyd9fShQ==
=Sbji
-----END PGP PUBLIC KEY BLOCK-----
+52
View File
@@ -0,0 +1,52 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: GPGTools - https://gpgtools.org
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
kY+BVpiLBOJa+eykxS15bw==
=xbPI
-----END PGP PUBLIC KEY BLOCK-----
+51
View File
@@ -0,0 +1,51 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=kst3
-----END PGP PUBLIC KEY BLOCK-----
+12
View File
@@ -0,0 +1,12 @@
Sample configuration files for:
```
SystemD: agrariand.service
Upstart: agrariand.conf
OpenRC: agrariand.openrc
agrariand.openrcconf
CentOS: agrariand.init
macOS: org.agrarian.agrariand.plist
```
have been made available to assist packagers in creating node packages here.
See doc/init.md for more information.
+63
View File
@@ -0,0 +1,63 @@
description "Agrarian Core Daemon"
start on runlevel [2345]
stop on starting rc RUNLEVEL=[016]
env BITCOIND_BIN="/usr/bin/agrariand"
env BITCOIND_USER="agrarian"
env BITCOIND_GROUP="agrarian"
env BITCOIND_PIDDIR="/var/run/agrariand"
# upstart can't handle variables constructed with other variables
env BITCOIND_PIDFILE="/var/run/agrariand/agrariand.pid"
env BITCOIND_CONFIGFILE="/etc/agrarian/agrarian.conf"
env BITCOIND_DATADIR="/var/lib/agrariand"
expect fork
respawn
respawn limit 5 120
kill timeout 60
pre-start script
# this will catch non-existent config files
# agrariand will check and exit with this very warning, but it can do so
# long after forking, leaving upstart to think everything started fine.
# since this is a commonly encountered case on install, just check and
# warn here.
if ! grep -qs '^rpcpassword=' "$BITCOIND_CONFIGFILE" ; then
echo "ERROR: You must set a secure rpcpassword to run agrariand."
echo "The setting must appear in $BITCOIND_CONFIGFILE"
echo
echo "This password is security critical to securing wallets "
echo "and must not be the same as the rpcuser setting."
echo "You can generate a suitable random password using the following"
echo "command from the shell:"
echo
echo "bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo'"
echo
echo "It is recommended that you also set alertnotify so you are "
echo "notified of problems:"
echo
echo "ie: alertnotify=echo %%s | mail -s \"Agrarian Alert\"" \
"admin@foo.com"
echo
exit 1
fi
mkdir -p "$BITCOIND_PIDDIR"
chmod 0755 "$BITCOIND_PIDDIR"
chown $BITCOIND_USER:$BITCOIND_GROUP "$BITCOIND_PIDDIR"
chown $BITCOIND_USER:$BITCOIND_GROUP "$BITCOIND_CONFIGFILE"
chmod 0660 "$BITCOIND_CONFIGFILE"
end script
exec start-stop-daemon \
--start \
--pidfile "$BITCOIND_PIDFILE" \
--chuid $BITCOIND_USER:$BITCOIND_GROUP \
--exec "$BITCOIND_BIN" \
-- \
-pid="$BITCOIND_PIDFILE" \
-conf="$BITCOIND_CONFIGFILE" \
-datadir="$BITCOIND_DATADIR" \
-daemon
+67
View File
@@ -0,0 +1,67 @@
#!/bin/bash
#
# agrariand The Agrarian core server.
#
#
# chkconfig: 345 80 20
# description: agrariand
# processname: agrariand
#
# Source function library.
. /etc/init.d/functions
# you can override defaults in /etc/sysconfig/agrariand, see below
if [ -f /etc/sysconfig/agrariand ]; then
. /etc/sysconfig/agrariand
fi
RETVAL=0
prog=agrariand
# you can override the lockfile via BITCOIND_LOCKFILE in /etc/sysconfig/agrariand
lockfile=${BITCOIND_LOCKFILE-/var/lock/subsys/agrariand}
# agrariand defaults to /usr/bin/agrariand, override with BITCOIND_BIN
bitcoind=${BITCOIND_BIN-/usr/bin/agrariand}
# agrariand opts default to -disablewallet, override with BITCOIND_OPTS
bitcoind_opts=${BITCOIND_OPTS}
start() {
echo -n $"Starting $prog: "
daemon $DAEMONOPTS $bitcoind $bitcoind_opts
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch $lockfile
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc $prog
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f $lockfile
return $RETVAL
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status $prog
;;
restart)
stop
start
;;
*)
echo "Usage: service $prog {start|stop|status|restart}"
exit 1
;;
esac
+92
View File
@@ -0,0 +1,92 @@
#!/sbin/openrc-run
# backward compatibility for existing gentoo layout
#
if [ -d "/var/lib/agrarian/.agrarian" ]; then
BITCOIND_DEFAULT_DATADIR="/var/lib/agrarian/.agrarian"
else
BITCOIND_DEFAULT_DATADIR="/var/lib/agrariand"
fi
BITCOIND_CONFIGFILE=${BITCOIND_CONFIGFILE:-/etc/agrarian/agrarian.conf}
BITCOIND_PIDDIR=${BITCOIND_PIDDIR:-/var/run/agrariand}
BITCOIND_PIDFILE=${BITCOIND_PIDFILE:-${BITCOIND_PIDDIR}/agrariand.pid}
BITCOIND_DATADIR=${BITCOIND_DATADIR:-${BITCOIND_DEFAULT_DATADIR}}
BITCOIND_USER=${BITCOIND_USER:-${BITCOIN_USER:-agrarian}
BITCOIND_GROUP=${BITCOIND_GROUP:-agrarian}
BITCOIND_BIN=${BITCOIND_BIN:-/usr/bin/agrariand}
BITCOIND_NICE=${BITCOIND_NICE:-${NICELEVEL:-0}}
BITCOIND_OPTS="${BITCOIND_OPTS:-${BITCOIN_OPTS}}"
name="Agrarian Core Daemon"
description="Agrarian crypto-currency p2p network daemon"
command="/usr/bin/agrariand"
command_args="-pid=\"${BITCOIND_PIDFILE}\" \
-conf=\"${BITCOIND_CONFIGFILE}\" \
-datadir=\"${BITCOIND_DATADIR}\" \
-daemon \
${BITCOIND_OPTS}"
required_files="${BITCOIND_CONFIGFILE}"
start_stop_daemon_args="-u ${BITCOIND_USER} \
-N ${BITCOIND_NICE} -w 2000"
pidfile="${BITCOIND_PIDFILE}"
# The retry schedule to use when stopping the daemon. Could be either
# a timeout in seconds or multiple signal/timeout pairs (like
# "SIGKILL/180 SIGTERM/300")
retry="${BITCOIND_SIGTERM_TIMEOUT}"
depend() {
need localmount net
}
# verify
# 1) that the datadir exists and is writable (or create it)
# 2) that a directory for the pid exists and is writable
# 3) ownership and permissions on the config file
start_pre() {
checkpath \
-d \
--mode 0750 \
--owner "${BITCOIND_USER}:${BITCOIND_GROUP}" \
"${BITCOIND_DATADIR}"
checkpath \
-d \
--mode 0755 \
--owner "${BITCOIND_USER}:${BITCOIND_GROUP}" \
"${BITCOIND_PIDDIR}"
checkpath -f \
-o ${BITCOIND_USER}:${BITCOIND_GROUP} \
-m 0660 \
${BITCOIND_CONFIGFILE}
checkconfig || return 1
}
checkconfig()
{
if ! grep -qs '^rpcpassword=' "${BITCOIND_CONFIGFILE}" ; then
eerror ""
eerror "ERROR: You must set a secure rpcpassword to run agrariand."
eerror "The setting must appear in ${BITCOIND_CONFIGFILE}"
eerror ""
eerror "This password is security critical to securing wallets "
eerror "and must not be the same as the rpcuser setting."
eerror "You can generate a suitable random password using the following"
eerror "command from the shell:"
eerror ""
eerror "bash -c 'tr -dc a-zA-Z0-9 < /dev/urandom | head -c32 && echo'"
eerror ""
eerror "It is recommended that you also set alertnotify so you are "
eerror "notified of problems:"
eerror ""
eerror "ie: alertnotify=echo %%s | mail -s \"Agrarian Alert\"" \
"admin@foo.com"
eerror ""
return 1
fi
}
+33
View File
@@ -0,0 +1,33 @@
# /etc/conf.d/agrariand: config file for /etc/init.d/agrariand
# Config file location
#BITCOIND_CONFIGFILE="/etc/agrarian/agrarian.conf"
# What directory to write pidfile to? (created and owned by $BITCOIND_USER)
#BITCOIND_PIDDIR="/var/run/agrariand"
# What filename to give the pidfile
#BITCOIND_PIDFILE="${BITCOIND_PIDDIR}/agrariand.pid"
# Where to write agrariand data (be mindful that the blockchain is large)
#BITCOIND_DATADIR="/var/lib/agrariand"
# User and group to own agrariand process
#BITCOIND_USER="agrarian"
#BITCOIND_GROUP="agrarian"
# Path to agrariand executable
#BITCOIND_BIN="/usr/bin/agrariand"
# Nice value to run agrariand under
#BITCOIND_NICE=0
# Additional options (avoid -conf and -datadir, use flags above)
#BITCOIND_OPTS=""
# The timeout in seconds OpenRC will wait for bitcoind to terminate
# after a SIGTERM has been raised.
# Note that this will be mapped as argument to start-stop-daemon's
# '--retry' option, which means you can specify a retry schedule
# here. For more information see man 8 start-stop-daemon.
BITCOIND_SIGTERM_TIMEOUT=60
+44
View File
@@ -0,0 +1,44 @@
# It is not recommended to modify this file in-place, because it will
# be overwritten during package upgrades. If you want to add further
# options or overwrite existing ones then use
# $ systemctl edit bitcoind.service
# See "man systemd.service" for details.
# Note that almost all daemon options could be specified in
# /etc/agrarian/agrarian.conf
[Unit]
Description=Agrarian daemon
After=network.target
[Service]
ExecStart=/usr/bin/agrariand -daemon -conf=/etc/agrarian/agrarian.conf -pid=/run/agrariand/agrariand.pid
# Creates /run/agrariand owned by agrarian
RuntimeDirectory=agrariand
User=agrarian
Type=forking
PIDFile=/run/agrariand/agrariand.pid
Restart=on-failure
# Hardening measures
####################
# Provide a private /tmp and /var/tmp.
PrivateTmp=true
# Mount /usr, /boot/ and /etc read-only for the process.
ProtectSystem=full
# Disallow the process and all of its children to gain
# new privileges through execve().
NoNewPrivileges=true
# Use a new /dev namespace only populated with API pseudo devices
# such as /dev/null, /dev/zero and /dev/random.
PrivateDevices=true
# Deny the creation of writable and executable memory mappings.
MemoryDenyWriteExecute=true
[Install]
WantedBy=multi-user.target
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>org.agrarian.agrariand</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/agrariand</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
+101
View File
@@ -0,0 +1,101 @@
#!/bin/sh
# Install libdb4.8 (Berkeley DB).
export LC_ALL=C
set -e
if [ -z "${1}" ]; then
echo "Usage: $0 <base-dir> [<extra-bdb-configure-flag> ...]"
echo
echo "Must specify a single argument: the directory in which db4 will be built."
echo "This is probably \`pwd\` if you're at the root of the agrarian repository."
exit 1
fi
expand_path() {
echo "$(cd "${1}" && pwd -P)"
}
BDB_PREFIX="$(expand_path ${1})/db4"; shift;
BDB_VERSION='db-4.8.30.NC'
BDB_HASH='12edc0df75bf9abd7f82f821795bcee50f42cb2e5f76a6a281b85732798364ef'
BDB_URL="https://download.oracle.com/berkeley-db/${BDB_VERSION}.tar.gz"
check_exists() {
which "$1" >/dev/null 2>&1
}
sha256_check() {
# Args: <sha256_hash> <filename>
#
if check_exists sha256sum; then
echo "${1} ${2}" | sha256sum -c
elif check_exists sha256; then
if [ "$(uname)" = "FreeBSD" ]; then
sha256 -c "${1}" "${2}"
else
echo "${1} ${2}" | sha256 -c
fi
else
echo "${1} ${2}" | shasum -a 256 -c
fi
}
http_get() {
# Args: <url> <filename> <sha256_hash>
#
# It's acceptable that we don't require SSL here because we manually verify
# content hashes below.
#
if [ -f "${2}" ]; then
echo "File ${2} already exists; not downloading again"
elif check_exists curl; then
curl --insecure --retry 5 "${1}" -o "${2}"
else
wget --no-check-certificate "${1}" -O "${2}"
fi
sha256_check "${3}" "${2}"
}
mkdir -p "${BDB_PREFIX}"
http_get "${BDB_URL}" "${BDB_VERSION}.tar.gz" "${BDB_HASH}"
tar -xzvf ${BDB_VERSION}.tar.gz -C "$BDB_PREFIX"
cd "${BDB_PREFIX}/${BDB_VERSION}/"
# Apply a patch necessary when building with clang and c++11 (see https://community.oracle.com/thread/3952592)
CLANG_CXX11_PATCH_URL='https://gist.githubusercontent.com/LnL7/5153b251fd525fe15de69b67e63a6075/raw/7778e9364679093a32dec2908656738e16b6bdcb/clang.patch'
CLANG_CXX11_PATCH_HASH='7a9a47b03fd5fb93a16ef42235fa9512db9b0829cfc3bdf90edd3ec1f44d637c'
http_get "${CLANG_CXX11_PATCH_URL}" clang.patch "${CLANG_CXX11_PATCH_HASH}"
patch -p2 < clang.patch
# The packaged config.guess and config.sub are ancient (2009) and can cause build issues.
# Replace them with modern versions.
# See https://github.com/bitcoin/bitcoin/issues/16064
CONFIG_GUESS_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=55eaf3e779455c4e5cc9f82efb5278be8f8f900b'
CONFIG_GUESS_HASH='2d1ff7bca773d2ec3c6217118129220fa72d8adda67c7d2bf79994b3129232c1'
CONFIG_SUB_URL='https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=55eaf3e779455c4e5cc9f82efb5278be8f8f900b'
CONFIG_SUB_HASH='3a4befde9bcdf0fdb2763fc1bfa74e8696df94e1ad7aac8042d133c8ff1d2e32'
rm -f "dist/config.guess"
rm -f "dist/config.sub"
http_get "${CONFIG_GUESS_URL}" dist/config.guess "${CONFIG_GUESS_HASH}"
http_get "${CONFIG_SUB_URL}" dist/config.sub "${CONFIG_SUB_HASH}"
cd build_unix/
"${BDB_PREFIX}/${BDB_VERSION}/dist/configure" \
--enable-cxx --disable-shared --disable-replication --with-pic --prefix="${BDB_PREFIX}" \
"${@}"
make install
echo
echo "db4 build complete."
echo
echo 'When compiling agrariand, run `./configure` in the following way:'
echo
echo " export BDB_PREFIX='${BDB_PREFIX}'"
echo ' ./configure BDB_LIBS="-L${BDB_PREFIX}/lib -ldb_cxx-4.8" BDB_CFLAGS="-I${BDB_PREFIX}/include" ...'
+33
View File
@@ -0,0 +1,33 @@
# Linearize
Construct a linear, no-fork, best version of the blockchain.
## Step 1: Download hash list
$ ./linearize-hashes.py linearize.cfg > hashlist.txt
Required configuration file settings for linearize-hashes:
* RPC: rpcuser, rpcpassword
Optional config file setting for linearize-hashes:
* RPC: host, port
* Block chain: min_height, max_height
## Step 2: Copy local block data
$ ./linearize-data.py linearize.cfg
Required configuration file settings:
* "input": bitcoind blocks/ directory containing blkNNNNN.dat
* "hashlist": text file containing list of block hashes, linearized-hashes.py
output.
* "output_file": bootstrap.dat
or
* "output": output directory for linearized blocks/blkNNNNN.dat output
Optional config file setting for linearize-data:
* "netmagic": network magic number
* "max_out_sz": maximum output file size (default 1000*1000*1000)
* "split_timestamp": Split files when a new month is first seen, in addition to
reaching a maximum file size.
* "file_timestamp": Set each file's last-modified time to that of the
most recent block in that file.
+19
View File
@@ -0,0 +1,19 @@
# bitcoind RPC settings (linearize-hashes)
rpcuser=someuser
rpcpassword=somepassword
host=127.0.0.1
port=51470
# bootstrap.dat hashlist settings (linearize-hashes)
max_height=313000
# bootstrap.dat input/output settings (linearize-data)
netmagic=90c4fde9
input=/home/example/.bitcoin/blocks
output_file=/home/example/Downloads/bootstrap.dat
hashlist=hashlist.txt
split_year=1
# Maxmimum size in bytes of out-of-order blocks cache in memory
out_of_order_cache_sz = 100000000
+299
View File
@@ -0,0 +1,299 @@
#!/usr/bin/python
#
# linearize-data.py: Construct a linear, no-fork version of the chain.
#
# Copyright (c) 2013-2014 The Bitcoin developers
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
from __future__ import print_function, division
import json
import struct
import re
import os
import base64
import httplib
import sys
import hashlib
import datetime
import time
from collections import namedtuple
settings = {}
def uint32(x):
return x & 0xffffffffL
def bytereverse(x):
return uint32(( ((x) << 24) | (((x) << 8) & 0x00ff0000) |
(((x) >> 8) & 0x0000ff00) | ((x) >> 24) ))
def bufreverse(in_buf):
out_words = []
for i in range(0, len(in_buf), 4):
word = struct.unpack('@I', in_buf[i:i+4])[0]
out_words.append(struct.pack('@I', bytereverse(word)))
return ''.join(out_words)
def wordreverse(in_buf):
out_words = []
for i in range(0, len(in_buf), 4):
out_words.append(in_buf[i:i+4])
out_words.reverse()
return ''.join(out_words)
def calc_hdr_hash(blk_hdr):
hash1 = hashlib.sha256()
hash1.update(blk_hdr)
hash1_o = hash1.digest()
hash2 = hashlib.sha256()
hash2.update(hash1_o)
hash2_o = hash2.digest()
return hash2_o
def calc_hash_str(blk_hdr):
hash = calc_hdr_hash(blk_hdr)
hash = bufreverse(hash)
hash = wordreverse(hash)
hash_str = hash.encode('hex')
return hash_str
def get_blk_dt(blk_hdr):
members = struct.unpack("<I", blk_hdr[68:68+4])
nTime = members[0]
dt = datetime.datetime.fromtimestamp(nTime)
dt_ym = datetime.datetime(dt.year, dt.month, 1)
return (dt_ym, nTime)
def get_block_hashes(settings):
blkindex = []
f = open(settings['hashlist'], "r")
for line in f:
line = line.rstrip()
blkindex.append(line)
print("Read " + str(len(blkindex)) + " hashes")
return blkindex
def mkblockmap(blkindex):
blkmap = {}
for height,hash in enumerate(blkindex):
blkmap[hash] = height
return blkmap
# Block header and extent on disk
BlockExtent = namedtuple('BlockExtent', ['fn', 'offset', 'inhdr', 'blkhdr', 'size'])
class BlockDataCopier:
def __init__(self, settings, blkindex, blkmap):
self.settings = settings
self.blkindex = blkindex
self.blkmap = blkmap
self.inFn = 0
self.inF = None
self.outFn = 0
self.outsz = 0
self.outF = None
self.outFname = None
self.blkCountIn = 0
self.blkCountOut = 0
self.lastDate = datetime.datetime(2000, 1, 1)
self.highTS = 1408893517 - 315360000
self.timestampSplit = False
self.fileOutput = True
self.setFileTime = False
self.maxOutSz = settings['max_out_sz']
if 'output' in settings:
self.fileOutput = False
if settings['file_timestamp'] != 0:
self.setFileTime = True
if settings['split_timestamp'] != 0:
self.timestampSplit = True
# Extents and cache for out-of-order blocks
self.blockExtents = {}
self.outOfOrderData = {}
self.outOfOrderSize = 0 # running total size for items in outOfOrderData
def writeBlock(self, inhdr, blk_hdr, rawblock):
if not self.fileOutput and ((self.outsz + self.inLen) > self.maxOutSz):
self.outF.close()
if self.setFileTime:
os.utime(outFname, (int(time.time()), highTS))
self.outF = None
self.outFname = None
self.outFn = outFn + 1
self.outsz = 0
(blkDate, blkTS) = get_blk_dt(blk_hdr)
if self.timestampSplit and (blkDate > self.lastDate):
print("New month " + blkDate.strftime("%Y-%m") + " @ " + hash_str)
lastDate = blkDate
if outF:
outF.close()
if setFileTime:
os.utime(outFname, (int(time.time()), highTS))
self.outF = None
self.outFname = None
self.outFn = self.outFn + 1
self.outsz = 0
if not self.outF:
if self.fileOutput:
outFname = self.settings['output_file']
else:
outFname = "%s/blk%05d.dat" % (self.settings['output'], outFn)
print("Output file" + outFname)
self.outF = open(outFname, "wb")
self.outF.write(inhdr)
self.outF.write(blk_hdr)
self.outF.write(rawblock)
self.outsz = self.outsz + len(inhdr) + len(blk_hdr) + len(rawblock)
self.blkCountOut = self.blkCountOut + 1
if blkTS > self.highTS:
self.highTS = blkTS
if (self.blkCountOut % 1000) == 0:
print('%i blocks scanned, %i blocks written (of %i, %.1f%% complete)' %
(self.blkCountIn, self.blkCountOut, len(self.blkindex), 100.0 * self.blkCountOut / len(self.blkindex)))
def inFileName(self, fn):
return "%s/blk%05d.dat" % (self.settings['input'], fn)
def fetchBlock(self, extent):
'''Fetch block contents from disk given extents'''
with open(self.inFileName(extent.fn), "rb") as f:
f.seek(extent.offset)
return f.read(extent.size)
def copyOneBlock(self):
'''Find the next block to be written in the input, and copy it to the output.'''
extent = self.blockExtents.pop(self.blkCountOut)
if self.blkCountOut in self.outOfOrderData:
# If the data is cached, use it from memory and remove from the cache
rawblock = self.outOfOrderData.pop(self.blkCountOut)
self.outOfOrderSize -= len(rawblock)
else: # Otherwise look up data on disk
rawblock = self.fetchBlock(extent)
self.writeBlock(extent.inhdr, extent.blkhdr, rawblock)
def run(self):
while self.blkCountOut < len(self.blkindex):
if not self.inF:
fname = self.inFileName(self.inFn)
print("Input file" + fname)
try:
self.inF = open(fname, "rb")
except IOError:
print("Premature end of block data")
return
inhdr = self.inF.read(8)
if (not inhdr or (inhdr[0] == "\0")):
self.inF.close()
self.inF = None
self.inFn = self.inFn + 1
continue
inMagic = inhdr[:4]
if (inMagic != self.settings['netmagic']):
print("Invalid magic:" + inMagic)
return
inLenLE = inhdr[4:]
su = struct.unpack("<I", inLenLE)
inLen = su[0] - 80 # length without header
blk_hdr = self.inF.read(80)
inExtent = BlockExtent(self.inFn, self.inF.tell(), inhdr, blk_hdr, inLen)
hash_str = calc_hash_str(blk_hdr)
if not hash_str in blkmap:
print("Skipping unknown block " + hash_str)
self.inF.seek(inLen, os.SEEK_CUR)
continue
blkHeight = self.blkmap[hash_str]
self.blkCountIn += 1
if self.blkCountOut == blkHeight:
# If in-order block, just copy
rawblock = self.inF.read(inLen)
self.writeBlock(inhdr, blk_hdr, rawblock)
# See if we can catch up to prior out-of-order blocks
while self.blkCountOut in self.blockExtents:
self.copyOneBlock()
else: # If out-of-order, skip over block data for now
self.blockExtents[blkHeight] = inExtent
if self.outOfOrderSize < self.settings['out_of_order_cache_sz']:
# If there is space in the cache, read the data
# Reading the data in file sequence instead of seeking and fetching it later is preferred,
# but we don't want to fill up memory
self.outOfOrderData[blkHeight] = self.inF.read(inLen)
self.outOfOrderSize += inLen
else: # If no space in cache, seek forward
self.inF.seek(inLen, os.SEEK_CUR)
print("Done (%i blocks written)" % (self.blkCountOut))
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: linearize-data.py CONFIG-FILE")
sys.exit(1)
f = open(sys.argv[1])
for line in f:
# skip comment lines
m = re.search('^\s*#', line)
if m:
continue
# parse key=value lines
m = re.search('^(\w+)\s*=\s*(\S.*)$', line)
if m is None:
continue
settings[m.group(1)] = m.group(2)
f.close()
if 'netmagic' not in settings:
settings['netmagic'] = 'f9beb4d9'
if 'input' not in settings:
settings['input'] = 'input'
if 'hashlist' not in settings:
settings['hashlist'] = 'hashlist.txt'
if 'file_timestamp' not in settings:
settings['file_timestamp'] = 0
if 'split_timestamp' not in settings:
settings['split_timestamp'] = 0
if 'max_out_sz' not in settings:
settings['max_out_sz'] = 1000L * 1000 * 1000
if 'out_of_order_cache_sz' not in settings:
settings['out_of_order_cache_sz'] = 100 * 1000 * 1000
settings['max_out_sz'] = long(settings['max_out_sz'])
settings['split_timestamp'] = int(settings['split_timestamp'])
settings['file_timestamp'] = int(settings['file_timestamp'])
settings['netmagic'] = settings['netmagic'].decode('hex')
settings['out_of_order_cache_sz'] = int(settings['out_of_order_cache_sz'])
if 'output_file' not in settings and 'output' not in settings:
print("Missing output file / directory")
sys.exit(1)
blkindex = get_block_hashes(settings)
blkmap = mkblockmap(blkindex)
if not "0000041e482b9b9691d98eefb48473405c0b8ec31b76df3797c74a78680ef818" in blkmap:
print("not found")
else:
BlockDataCopier(settings, blkindex, blkmap).run()
+113
View File
@@ -0,0 +1,113 @@
#!/usr/bin/python
#
# linearize-hashes.py: List blocks in a linear, no-fork version of the chain.
#
# Copyright (c) 2013-2014 The Bitcoin developers
# Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
#
from __future__ import print_function
import json
import struct
import re
import base64
import httplib
import sys
settings = {}
class BitcoinRPC:
def __init__(self, host, port, username, password):
authpair = "%s:%s" % (username, password)
self.authhdr = "Basic %s" % (base64.b64encode(authpair))
self.conn = httplib.HTTPConnection(host, port, False, 30)
def execute(self, obj):
self.conn.request('POST', '/', json.dumps(obj),
{ 'Authorization' : self.authhdr,
'Content-type' : 'application/json' })
resp = self.conn.getresponse()
if resp is None:
print("JSON-RPC: no response", file=sys.stderr)
return None
body = resp.read()
resp_obj = json.loads(body)
return resp_obj
@staticmethod
def build_request(idx, method, params):
obj = { 'version' : '1.1',
'method' : method,
'id' : idx }
if params is None:
obj['params'] = []
else:
obj['params'] = params
return obj
@staticmethod
def response_is_error(resp_obj):
return 'error' in resp_obj and resp_obj['error'] is not None
def get_block_hashes(settings, max_blocks_per_call=10000):
rpc = BitcoinRPC(settings['host'], settings['port'],
settings['rpcuser'], settings['rpcpassword'])
height = settings['min_height']
while height < settings['max_height']+1:
num_blocks = min(settings['max_height']+1-height, max_blocks_per_call)
batch = []
for x in range(num_blocks):
batch.append(rpc.build_request(x, 'getblockhash', [height + x]))
reply = rpc.execute(batch)
for x,resp_obj in enumerate(reply):
if rpc.response_is_error(resp_obj):
print('JSON-RPC: error at height', height+x, ': ', resp_obj['error'], file=sys.stderr)
exit(1)
assert(resp_obj['id'] == x) # assume replies are in-sequence
print(resp_obj['result'])
height += num_blocks
if __name__ == '__main__':
if len(sys.argv) != 2:
print("Usage: linearize-hashes.py CONFIG-FILE")
sys.exit(1)
f = open(sys.argv[1])
for line in f:
# skip comment lines
m = re.search('^\s*#', line)
if m:
continue
# parse key=value lines
m = re.search('^(\w+)\s*=\s*(\S.*)$', line)
if m is None:
continue
settings[m.group(1)] = m.group(2)
f.close()
if 'host' not in settings:
settings['host'] = '127.0.0.1'
if 'port' not in settings:
settings['port'] = 51335
if 'min_height' not in settings:
settings['min_height'] = 0
if 'max_height' not in settings:
settings['max_height'] = 313000
if 'rpcuser' not in settings or 'rpcpassword' not in settings:
print("Missing username and/or password in cfg file", file=stderr)
sys.exit(1)
settings['port'] = int(settings['port'])
settings['min_height'] = int(settings['min_height'])
settings['max_height'] = int(settings['max_height'])
get_block_hashes(settings)
+674
View File
@@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+15
View File
@@ -0,0 +1,15 @@
### MacDeploy ###
For Snow Leopard (which uses [Python 2.6](http://www.python.org/download/releases/2.6/)), you will need the param_parser package:
sudo easy_install argparse
This script should not be run manually, instead, after building as usual:
make deploy
During the process, the disk image window will pop up briefly where the fancy
settings are applied. This is normal, please do not interfere.
When finished, it will produce `Agrarian-Qt.dmg`.
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="1000pt" height="640pt" viewBox="0 0 1000 640" preserveAspectRatio="xMidYMid meet">
<!-- kate: space-indent off;
Copyright (c) 2015 The Bitcoin Core developers
Distributed under the MIT software license, see the accompanying
file COPYING or http://www.opensource.org/licenses/mit-license.php.
-->
<style type="text/css"><![CDATA[
text {
font-family: "Tuffy";
font-size: 86px;
fill: gray;
text-anchor: middle;
}
]]></style>
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" style="stop-color:rgb(239,239,239);stop-opacity:1" />
<stop offset="33%" style="stop-color:rgb(239,239,239);stop-opacity:1" />
<stop offset="80%" style="stop-color:rgb(205,205,205);stop-opacity:1" />
<stop offset="100%" style="stop-color:rgb(204,204,204);stop-opacity:1" />
</linearGradient>
</defs>
<rect width="1000" height="640" style="fill:url(#gradient);stroke-width:0" />
<g transform="translate(500,0) scale(0.9, 1)">
<text x="0" y="114">PACKAGE_NAME</text>
</g>
<g transform="translate(0.000000,640.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M4995 3705 c-24 -23 -25 -29 -25 -165 l0 -140 -306 0 -306 0 -29 -29 c-29 -29 -29 -31 -29 -141 0 -110 0 -112 29 -141 l29 -29 306 0 306 0 0 -140 c0 -136 1 -142 25 -165 16 -17 35 -25 57 -25 29 0 72 32 306 226 180 149 274 233 278 250 13 53 -2 70 -278 299 -235 194 -277 225 -306 225 -22 0 -41 -8 -57 -25z" fixlter="url(#glow)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env python3
# Copyright (c) 2013-2017 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
import biplist
from ds_store import DSStore
from mac_alias import Alias
import sys
output_file = sys.argv[1]
package_name_ns = sys.argv[2]
ds = DSStore.open(output_file, 'w+')
ds['.']['bwsp'] = {
'ShowStatusBar': False,
'WindowBounds': '{{300, 280}, {500, 343}}',
'ContainerShowSidebar': False,
'SidebarWidth': 0,
'ShowTabView': False,
'PreviewPaneVisibility': False,
'ShowToolbar': False,
'ShowSidebar': False,
'ShowPathbar': True
}
icvp = {
'gridOffsetX': 0.0,
'textSize': 12.0,
'viewOptionsVersion': 1,
'backgroundImageAlias': b'\x00\x00\x00\x00\x02\x1e\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd1\x94\\\xb0H+\x00\x05\x00\x00\x00\x98\x0fbackground.tiff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x99\xd19\xb0\xf8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x00\x00\r\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0b.background\x00\x00\x10\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x11\x00\x08\x00\x00\xd19\xb0\xf8\x00\x00\x00\x01\x00\x04\x00\x00\x00\x98\x00\x0e\x00 \x00\x0f\x00b\x00a\x00c\x00k\x00g\x00r\x00o\x00u\x00n\x00d\x00.\x00t\x00i\x00f\x00f\x00\x0f\x00\x02\x00\x00\x00\x12\x00\x1c/.background/background.tiff\x00\x14\x01\x06\x00\x00\x00\x00\x01\x06\x00\x02\x00\x00\x0cMacintosh HD\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xce\x97\xab\xc3H+\x00\x00\x01\x88[\x88\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02u\xab\x8d\xd1\x94\\\xb0devrddsk\xff\xff\xff\xff\x00\x00\t \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07bitcoin\x00\x00\x10\x00\x08\x00\x00\xce\x97\xab\xc3\x00\x00\x00\x11\x00\x08\x00\x00\xd1\x94\\\xb0\x00\x00\x00\x01\x00\x14\x01\x88[\x88\x00\x16\xa9\t\x00\x08\xfaR\x00\x08\xfaQ\x00\x02d\x8e\x00\x0e\x00\x02\x00\x00\x00\x0f\x00\x1a\x00\x0c\x00M\x00a\x00c\x00i\x00n\x00t\x00o\x00s\x00h\x00 \x00H\x00D\x00\x13\x00\x01/\x00\x00\x15\x00\x02\x00\x14\xff\xff\x00\x00\xff\xff\x00\x00',
'backgroundColorBlue': 1.0,
'iconSize': 96.0,
'backgroundColorGreen': 1.0,
'arrangeBy': 'none',
'showIconPreview': True,
'gridSpacing': 100.0,
'gridOffsetY': 0.0,
'showItemInfo': False,
'labelOnBottom': True,
'backgroundType': 2,
'backgroundColorRed': 1.0
}
alias = Alias.from_bytes(icvp['backgroundImageAlias'])
alias.volume.name = package_name_ns
alias.volume.posix_path = '/Volumes/' + package_name_ns
alias.volume.disk_image_alias.target.filename = package_name_ns + '.temp.dmg'
alias.volume.disk_image_alias.target.carbon_path = 'Macintosh HD:Users:\x00bitcoinuser:\x00Documents:\x00bitcoin:\x00bitcoin:\x00' + package_name_ns + '.temp.dmg'
alias.volume.disk_image_alias.target.posix_path = 'Users/bitcoinuser/Documents/bitcoin/bitcoin/' + package_name_ns + '.temp.dmg'
alias.target.carbon_path = package_name_ns + ':.background:\x00background.tiff'
icvp['backgroundImageAlias'] = biplist.Data(alias.to_bytes())
ds['.']['icvp'] = icvp
ds['.']['vSrn'] = ('long', 1)
ds['Applications']['Iloc'] = (370, 156)
ds['Agrarian-Qt.app']['Iloc'] = (128, 156)
ds.flush()
ds.close()
+57
View File
@@ -0,0 +1,57 @@
#!/bin/sh
# Copyright (c) 2014-2015 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C
set -e
UNSIGNED="$1"
SIGNATURE="$2"
ARCH=x86_64
ROOTDIR=dist
TEMPDIR=signed.temp
OUTDIR=signed-app
if [ -z "$UNSIGNED" ]; then
echo "usage: $0 <unsigned app> <signature>"
exit 1
fi
if [ -z "$SIGNATURE" ]; then
echo "usage: $0 <unsigned app> <signature>"
exit 1
fi
rm -rf ${TEMPDIR} && mkdir -p ${TEMPDIR}
tar -C ${TEMPDIR} -xf ${UNSIGNED}
cp -rf "${SIGNATURE}"/* ${TEMPDIR}
if [ -z "${PAGESTUFF}" ]; then
PAGESTUFF=${TEMPDIR}/pagestuff
fi
if [ -z "${CODESIGN_ALLOCATE}" ]; then
CODESIGN_ALLOCATE=${TEMPDIR}/codesign_allocate
fi
find ${TEMPDIR} -name "*.sign" | while read i; do
SIZE=`stat -c %s "${i}"`
TARGET_FILE="`echo "${i}" | sed 's/\.sign$//'`"
echo "Allocating space for the signature of size ${SIZE} in ${TARGET_FILE}"
${CODESIGN_ALLOCATE} -i "${TARGET_FILE}" -a ${ARCH} ${SIZE} -o "${i}.tmp"
OFFSET=`${PAGESTUFF} "${i}.tmp" -p | tail -2 | grep offset | sed 's/[^0-9]*//g'`
if [ -z ${QUIET} ]; then
echo "Attaching signature at offset ${OFFSET}"
fi
dd if="$i" of="${i}.tmp" bs=1 seek=${OFFSET} count=${SIZE} 2>/dev/null
mv "${i}.tmp" "${TARGET_FILE}"
rm "${i}"
echo "Success."
done
mv ${TEMPDIR}/${ROOTDIR} ${OUTDIR}
rm -rf ${TEMPDIR}
echo "Signed: ${OUTDIR}"
+52
View File
@@ -0,0 +1,52 @@
#!/bin/sh
# Copyright (c) 2014-2015 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C
set -e
ROOTDIR=dist
BUNDLE=${ROOTDIR}/Agrarian-Qt.app
CODESIGN=codesign
TEMPDIR=sign.temp
TEMPLIST=${TEMPDIR}/signatures.txt
OUT=signature-osx.tar.gz
OUTROOT=osx
if [ ! -n "$1" ]; then
echo "usage: $0 <codesign args>"
echo "example: $0 -s MyIdentity"
exit 1
fi
rm -rf ${TEMPDIR} ${TEMPLIST}
mkdir -p ${TEMPDIR}
${CODESIGN} -f --file-list ${TEMPLIST} "$@" "${BUNDLE}"
grep -v CodeResources < "${TEMPLIST}" | while read i; do
TARGETFILE="${BUNDLE}/`echo "${i}" | sed "s|.*${BUNDLE}/||"`"
SIZE=`pagestuff "$i" -p | tail -2 | grep size | sed 's/[^0-9]*//g'`
OFFSET=`pagestuff "$i" -p | tail -2 | grep offset | sed 's/[^0-9]*//g'`
SIGNFILE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}.sign"
DIRNAME="`dirname "${SIGNFILE}"`"
mkdir -p "${DIRNAME}"
echo "Adding detached signature for: ${TARGETFILE}. Size: ${SIZE}. Offset: ${OFFSET}"
dd if="$i" of="${SIGNFILE}" bs=1 skip=${OFFSET} count=${SIZE} 2>/dev/null
done
grep CodeResources < "${TEMPLIST}" | while read i; do
TARGETFILE="${BUNDLE}/`echo "${i}" | sed "s|.*${BUNDLE}/||"`"
RESOURCE="${TEMPDIR}/${OUTROOT}/${TARGETFILE}"
DIRNAME="`dirname "${RESOURCE}"`"
mkdir -p "${DIRNAME}"
echo "Adding resource for: \"${TARGETFILE}\""
cp "${i}" "${RESOURCE}"
done
rm ${TEMPLIST}
tar -C "${TEMPDIR}" -czf "${OUT}" .
rm -rf "${TEMPDIR}"
echo "Created ${OUT}"
+34
View File
@@ -0,0 +1,34 @@
#!/usr/bin/env bash
# Copyright (c) 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
export LC_ALL=C
set -e
INPUTFILE="Xcode_7.3.1.dmg"
HFSFILENAME="5.hfs"
SDKDIR="Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk"
7z x "${INPUTFILE}" "${HFSFILENAME}"
SDKNAME="$(basename "${SDKDIR}")"
SDKDIRINODE=$(ifind -n "${SDKDIR}" "${HFSFILENAME}")
fls "${HFSFILENAME}" -rpF ${SDKDIRINODE} |
while read type inode filename; do
inode="${inode::-1}"
if [ "${filename:0:14}" = "usr/share/man/" ]; then
continue
fi
filename="${SDKNAME}/$filename"
echo "Extracting $filename ..."
mkdir -p "$(dirname "$filename")"
if [ "$type" = "l/l" ]; then
ln -s "$(icat "${HFSFILENAME}" $inode)" "$filename"
else
icat "${HFSFILENAME}" $inode >"$filename"
fi
done
echo "Building ${SDKNAME}.tar.gz ..."
MTIME="$(istat "${HFSFILENAME}" "${SDKDIRINODE}" | perl -nle 'm/Content Modified:\s+(.*?)\s\(/ && print $1')"
find "${SDKNAME}" | sort | tar --no-recursion --mtime="${MTIME}" --mode='u+rw,go+r-w,a+X' --owner=0 --group=0 -c -T - | gzip -9n > "${SDKNAME}.tar.gz"
echo 'All done!'
+32
View File
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>window_bounds</key>
<array>
<integer>300</integer>
<integer>300</integer>
<integer>800</integer>
<integer>620</integer>
</array>
<key>background_picture</key>
<string>background.tiff</string>
<key>icon_size</key>
<integer>96</integer>
<key>applications_symlink</key>
<true/>
<key>items_position</key>
<dict>
<key>Applications</key>
<array>
<integer>370</integer>
<integer>156</integer>
</array>
<key>Agrarian-Qt.app</key>
<array>
<integer>128</integer>
<integer>156</integer>
</array>
</dict>
</dict>
</plist>
+872
View File
@@ -0,0 +1,872 @@
#!/usr/bin/env python3
#
# Copyright (C) 2011 Patrick "p2k" Schneider <me@p2k-network.org>
#
# 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 subprocess, sys, re, os, shutil, stat, os.path, time
from string import Template
from argparse import ArgumentParser
# This is ported from the original macdeployqt with modifications
class FrameworkInfo(object):
def __init__(self):
self.frameworkDirectory = ""
self.frameworkName = ""
self.frameworkPath = ""
self.binaryDirectory = ""
self.binaryName = ""
self.binaryPath = ""
self.version = ""
self.installName = ""
self.deployedInstallName = ""
self.sourceFilePath = ""
self.destinationDirectory = ""
self.sourceResourcesDirectory = ""
self.sourceVersionContentsDirectory = ""
self.sourceContentsDirectory = ""
self.destinationResourcesDirectory = ""
self.destinationVersionContentsDirectory = ""
def __eq__(self, other):
if self.__class__ == other.__class__:
return self.__dict__ == other.__dict__
else:
return False
def __str__(self):
return """ Framework name: %s
Framework directory: %s
Framework path: %s
Binary name: %s
Binary directory: %s
Binary path: %s
Version: %s
Install name: %s
Deployed install name: %s
Source file Path: %s
Deployed Directory (relative to bundle): %s
""" % (self.frameworkName,
self.frameworkDirectory,
self.frameworkPath,
self.binaryName,
self.binaryDirectory,
self.binaryPath,
self.version,
self.installName,
self.deployedInstallName,
self.sourceFilePath,
self.destinationDirectory)
def isDylib(self):
return self.frameworkName.endswith(".dylib")
def isQtFramework(self):
if self.isDylib():
return self.frameworkName.startswith("libQt")
else:
return self.frameworkName.startswith("Qt")
reOLine = re.compile(r'^(.+) \(compatibility version [0-9.]+, current version [0-9.]+\)$')
bundleFrameworkDirectory = "Contents/Frameworks"
bundleBinaryDirectory = "Contents/MacOS"
@classmethod
def fromOtoolLibraryLine(cls, line):
# Note: line must be trimmed
if line == "":
return None
# Don't deploy system libraries (exception for libQtuitools and libQtlucene).
if line.startswith("/System/Library/") or line.startswith("@executable_path") or (line.startswith("/usr/lib/") and "libQt" not in line):
return None
m = cls.reOLine.match(line)
if m is None:
raise RuntimeError("otool line could not be parsed: " + line)
path = m.group(1)
info = cls()
info.sourceFilePath = path
info.installName = path
if path.endswith(".dylib"):
dirname, filename = os.path.split(path)
info.frameworkName = filename
info.frameworkDirectory = dirname
info.frameworkPath = path
info.binaryDirectory = dirname
info.binaryName = filename
info.binaryPath = path
info.version = "-"
info.installName = path
info.deployedInstallName = "@executable_path/../Frameworks/" + info.binaryName
info.sourceFilePath = path
info.destinationDirectory = cls.bundleFrameworkDirectory
else:
parts = path.split("/")
i = 0
# Search for the .framework directory
for part in parts:
if part.endswith(".framework"):
break
i += 1
if i == len(parts):
raise RuntimeError("Could not find .framework or .dylib in otool line: " + line)
info.frameworkName = parts[i]
info.frameworkDirectory = "/".join(parts[:i])
info.frameworkPath = os.path.join(info.frameworkDirectory, info.frameworkName)
info.binaryName = parts[i+3]
info.binaryDirectory = "/".join(parts[i+1:i+3])
info.binaryPath = os.path.join(info.binaryDirectory, info.binaryName)
info.version = parts[i+2]
info.deployedInstallName = "@executable_path/../Frameworks/" + os.path.join(info.frameworkName, info.binaryPath)
info.destinationDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, info.binaryDirectory)
info.sourceResourcesDirectory = os.path.join(info.frameworkPath, "Resources")
info.sourceContentsDirectory = os.path.join(info.frameworkPath, "Contents")
info.sourceVersionContentsDirectory = os.path.join(info.frameworkPath, "Versions", info.version, "Contents")
info.destinationResourcesDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Resources")
info.destinationContentsDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Contents")
info.destinationVersionContentsDirectory = os.path.join(cls.bundleFrameworkDirectory, info.frameworkName, "Versions", info.version, "Contents")
return info
class ApplicationBundleInfo(object):
def __init__(self, path):
self.path = path
appName = "Agrarian-Qt"
self.binaryPath = os.path.join(path, "Contents", "MacOS", appName)
if not os.path.exists(self.binaryPath):
raise RuntimeError("Could not find bundle binary for " + path)
self.resourcesPath = os.path.join(path, "Contents", "Resources")
self.pluginPath = os.path.join(path, "Contents", "PlugIns")
class DeploymentInfo(object):
def __init__(self):
self.qtPath = None
self.pluginPath = None
self.deployedFrameworks = []
def detectQtPath(self, frameworkDirectory):
parentDir = os.path.dirname(frameworkDirectory)
if os.path.exists(os.path.join(parentDir, "translations")):
# Classic layout, e.g. "/usr/local/Trolltech/Qt-4.x.x"
self.qtPath = parentDir
elif os.path.exists(os.path.join(parentDir, "share", "qt4", "translations")):
# MacPorts layout, e.g. "/opt/local/share/qt4"
self.qtPath = os.path.join(parentDir, "share", "qt4")
elif os.path.exists(os.path.join(os.path.dirname(parentDir), "share", "qt4", "translations")):
# Newer Macports layout
self.qtPath = os.path.join(os.path.dirname(parentDir), "share", "qt4")
else:
self.qtPath = os.getenv("QTDIR", None)
if self.qtPath is not None:
pluginPath = os.path.join(self.qtPath, "plugins")
if os.path.exists(pluginPath):
self.pluginPath = pluginPath
def usesFramework(self, name):
nameDot = "%s." % name
libNameDot = "lib%s." % name
for framework in self.deployedFrameworks:
if framework.endswith(".framework"):
if framework.startswith(nameDot):
return True
elif framework.endswith(".dylib"):
if framework.startswith(libNameDot):
return True
return False
def getFrameworks(binaryPath, verbose):
if verbose >= 3:
print("Inspecting with otool: " + binaryPath)
otoolbin=os.getenv("OTOOL", "otool")
otool = subprocess.Popen([otoolbin, "-L", binaryPath], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
o_stdout, o_stderr = otool.communicate()
if otool.returncode != 0:
if verbose >= 1:
sys.stderr.write(o_stderr)
sys.stderr.flush()
raise RuntimeError("otool failed with return code %d" % otool.returncode)
otoolLines = o_stdout.split("\n")
otoolLines.pop(0) # First line is the inspected binary
if ".framework" in binaryPath or binaryPath.endswith(".dylib"):
otoolLines.pop(0) # Frameworks and dylibs list themselves as a dependency.
libraries = []
for line in otoolLines:
line = line.replace("@loader_path", os.path.dirname(binaryPath))
info = FrameworkInfo.fromOtoolLibraryLine(line.strip())
if info is not None:
if verbose >= 3:
print("Found framework:")
print(info)
libraries.append(info)
return libraries
def runInstallNameTool(action, *args):
installnametoolbin=os.getenv("INSTALLNAMETOOL", "install_name_tool")
subprocess.check_call([installnametoolbin, "-"+action] + list(args))
def changeInstallName(oldName, newName, binaryPath, verbose):
if verbose >= 3:
print("Using install_name_tool:")
print(" in", binaryPath)
print(" change reference", oldName)
print(" to", newName)
runInstallNameTool("change", oldName, newName, binaryPath)
def changeIdentification(id, binaryPath, verbose):
if verbose >= 3:
print("Using install_name_tool:")
print(" change identification in", binaryPath)
print(" to", id)
runInstallNameTool("id", id, binaryPath)
def runStrip(binaryPath, verbose):
stripbin=os.getenv("STRIP", "strip")
if verbose >= 3:
print("Using strip:")
print(" stripped", binaryPath)
subprocess.check_call([stripbin, "-x", binaryPath])
def copyFramework(framework, path, verbose):
if framework.sourceFilePath.startswith("Qt"):
#standard place for Nokia Qt installer's frameworks
fromPath = "/Library/Frameworks/" + framework.sourceFilePath
else:
fromPath = framework.sourceFilePath
toDir = os.path.join(path, framework.destinationDirectory)
toPath = os.path.join(toDir, framework.binaryName)
if not os.path.exists(fromPath):
raise RuntimeError("No file at " + fromPath)
if os.path.exists(toPath):
return None # Already there
if not os.path.exists(toDir):
os.makedirs(toDir)
shutil.copy2(fromPath, toPath)
if verbose >= 3:
print("Copied:", fromPath)
print(" to:", toPath)
permissions = os.stat(toPath)
if not permissions.st_mode & stat.S_IWRITE:
os.chmod(toPath, permissions.st_mode | stat.S_IWRITE)
if not framework.isDylib(): # Copy resources for real frameworks
linkfrom = os.path.join(path, "Contents","Frameworks", framework.frameworkName, "Versions", "Current")
linkto = framework.version
if not os.path.exists(linkfrom):
os.symlink(linkto, linkfrom)
if verbose >= 2:
print("Linked:", linkfrom, "->", linkto)
fromResourcesDir = framework.sourceResourcesDirectory
if os.path.exists(fromResourcesDir):
toResourcesDir = os.path.join(path, framework.destinationResourcesDirectory)
shutil.copytree(fromResourcesDir, toResourcesDir, symlinks=True)
if verbose >= 3:
print("Copied resources:", fromResourcesDir)
print(" to:", toResourcesDir)
fromContentsDir = framework.sourceVersionContentsDirectory
if not os.path.exists(fromContentsDir):
fromContentsDir = framework.sourceContentsDirectory
if os.path.exists(fromContentsDir):
toContentsDir = os.path.join(path, framework.destinationVersionContentsDirectory)
shutil.copytree(fromContentsDir, toContentsDir, symlinks=True)
if verbose >= 3:
print("Copied Contents:", fromContentsDir)
print(" to:", toContentsDir)
elif framework.frameworkName.startswith("libQtGui"): # Copy qt_menu.nib (applies to non-framework layout)
qtMenuNibSourcePath = os.path.join(framework.frameworkDirectory, "Resources", "qt_menu.nib")
qtMenuNibDestinationPath = os.path.join(path, "Contents", "Resources", "qt_menu.nib")
if os.path.exists(qtMenuNibSourcePath) and not os.path.exists(qtMenuNibDestinationPath):
shutil.copytree(qtMenuNibSourcePath, qtMenuNibDestinationPath, symlinks=True)
if verbose >= 3:
print("Copied for libQtGui:", qtMenuNibSourcePath)
print(" to:", qtMenuNibDestinationPath)
return toPath
def deployFrameworks(frameworks, bundlePath, binaryPath, strip, verbose, deploymentInfo=None):
if deploymentInfo is None:
deploymentInfo = DeploymentInfo()
while len(frameworks) > 0:
framework = frameworks.pop(0)
deploymentInfo.deployedFrameworks.append(framework.frameworkName)
if verbose >= 2:
print("Processing", framework.frameworkName, "...")
# Get the Qt path from one of the Qt frameworks
if deploymentInfo.qtPath is None and framework.isQtFramework():
deploymentInfo.detectQtPath(framework.frameworkDirectory)
if framework.installName.startswith("@executable_path") or framework.installName.startswith(bundlePath):
if verbose >= 2:
print(framework.frameworkName, "already deployed, skipping.")
continue
# install_name_tool the new id into the binary
changeInstallName(framework.installName, framework.deployedInstallName, binaryPath, verbose)
# Copy framework to app bundle.
deployedBinaryPath = copyFramework(framework, bundlePath, verbose)
# Skip the rest if already was deployed.
if deployedBinaryPath is None:
continue
if strip:
runStrip(deployedBinaryPath, verbose)
# install_name_tool it a new id.
changeIdentification(framework.deployedInstallName, deployedBinaryPath, verbose)
# Check for framework dependencies
dependencies = getFrameworks(deployedBinaryPath, verbose)
for dependency in dependencies:
changeInstallName(dependency.installName, dependency.deployedInstallName, deployedBinaryPath, verbose)
# Deploy framework if necessary.
if dependency.frameworkName not in deploymentInfo.deployedFrameworks and dependency not in frameworks:
frameworks.append(dependency)
return deploymentInfo
def deployFrameworksForAppBundle(applicationBundle, strip, verbose):
frameworks = getFrameworks(applicationBundle.binaryPath, verbose)
if len(frameworks) == 0 and verbose >= 1:
print("Warning: Could not find any external frameworks to deploy in %s." % (applicationBundle.path))
return DeploymentInfo()
else:
return deployFrameworks(frameworks, applicationBundle.path, applicationBundle.binaryPath, strip, verbose)
def deployPlugins(appBundleInfo, deploymentInfo, strip, verbose):
# Lookup available plugins, exclude unneeded
plugins = []
if deploymentInfo.pluginPath is None:
return
for dirpath, dirnames, filenames in os.walk(deploymentInfo.pluginPath):
pluginDirectory = os.path.relpath(dirpath, deploymentInfo.pluginPath)
if pluginDirectory == "designer":
# Skip designer plugins
continue
elif pluginDirectory == "phonon" or pluginDirectory == "phonon_backend":
# Deploy the phonon plugins only if phonon is in use
if not deploymentInfo.usesFramework("phonon"):
continue
elif pluginDirectory == "sqldrivers":
# Deploy the sql plugins only if QtSql is in use
if not deploymentInfo.usesFramework("QtSql"):
continue
elif pluginDirectory == "script":
# Deploy the script plugins only if QtScript is in use
if not deploymentInfo.usesFramework("QtScript"):
continue
elif pluginDirectory == "qmltooling" or pluginDirectory == "qml1tooling":
# Deploy the qml plugins only if QtDeclarative is in use
if not deploymentInfo.usesFramework("QtDeclarative"):
continue
elif pluginDirectory == "bearer":
# Deploy the bearer plugins only if QtNetwork is in use
if not deploymentInfo.usesFramework("QtNetwork"):
continue
elif pluginDirectory == "position":
# Deploy the position plugins only if QtPositioning is in use
if not deploymentInfo.usesFramework("QtPositioning"):
continue
elif pluginDirectory == "sensors" or pluginDirectory == "sensorgestures":
# Deploy the sensor plugins only if QtSensors is in use
if not deploymentInfo.usesFramework("QtSensors"):
continue
elif pluginDirectory == "audio" or pluginDirectory == "playlistformats":
# Deploy the audio plugins only if QtMultimedia is in use
if not deploymentInfo.usesFramework("QtMultimedia"):
continue
elif pluginDirectory == "mediaservice":
# Deploy the mediaservice plugins only if QtMultimediaWidgets is in use
if not deploymentInfo.usesFramework("QtMultimediaWidgets"):
continue
for pluginName in filenames:
pluginPath = os.path.join(pluginDirectory, pluginName)
if pluginName.endswith("_debug.dylib"):
# Skip debug plugins
continue
elif pluginPath == "imageformats/libqsvg.dylib" or pluginPath == "iconengines/libqsvgicon.dylib":
# Deploy the svg plugins only if QtSvg is in use
if not deploymentInfo.usesFramework("QtSvg"):
continue
elif pluginPath == "accessible/libqtaccessiblecompatwidgets.dylib":
# Deploy accessibility for Qt3Support only if the Qt3Support is in use
if not deploymentInfo.usesFramework("Qt3Support"):
continue
elif pluginPath == "graphicssystems/libqglgraphicssystem.dylib":
# Deploy the opengl graphicssystem plugin only if QtOpenGL is in use
if not deploymentInfo.usesFramework("QtOpenGL"):
continue
elif pluginPath == "accessible/libqtaccessiblequick.dylib":
# Deploy the accessible qtquick plugin only if QtQuick is in use
if not deploymentInfo.usesFramework("QtQuick"):
continue
plugins.append((pluginDirectory, pluginName))
for pluginDirectory, pluginName in plugins:
if verbose >= 2:
print("Processing plugin", os.path.join(pluginDirectory, pluginName), "...")
sourcePath = os.path.join(deploymentInfo.pluginPath, pluginDirectory, pluginName)
destinationDirectory = os.path.join(appBundleInfo.pluginPath, pluginDirectory)
if not os.path.exists(destinationDirectory):
os.makedirs(destinationDirectory)
destinationPath = os.path.join(destinationDirectory, pluginName)
shutil.copy2(sourcePath, destinationPath)
if verbose >= 3:
print("Copied:", sourcePath)
print(" to:", destinationPath)
if strip:
runStrip(destinationPath, verbose)
dependencies = getFrameworks(destinationPath, verbose)
for dependency in dependencies:
changeInstallName(dependency.installName, dependency.deployedInstallName, destinationPath, verbose)
# Deploy framework if necessary.
if dependency.frameworkName not in deploymentInfo.deployedFrameworks:
deployFrameworks([dependency], appBundleInfo.path, destinationPath, strip, verbose, deploymentInfo)
qt_conf="""[Paths]
Translations=Resources
Plugins=PlugIns
"""
ap = ArgumentParser(description="""Improved version of macdeployqt.
Outputs a ready-to-deploy app in a folder "dist" and optionally wraps it in a .dmg file.
Note, that the "dist" folder will be deleted before deploying on each run.
Optionally, Qt translation files (.qm) and additional resources can be added to the bundle.
Also optionally signs the .app bundle; set the CODESIGNARGS environment variable to pass arguments
to the codesign tool.
E.g. CODESIGNARGS='--sign "Developer ID Application: ..." --keychain /encrypted/foo.keychain'""")
ap.add_argument("app_bundle", nargs=1, metavar="app-bundle", help="application bundle to be deployed")
ap.add_argument("-verbose", type=int, nargs=1, default=[1], metavar="<0-3>", help="0 = no output, 1 = error/warning (default), 2 = normal, 3 = debug")
ap.add_argument("-no-plugins", dest="plugins", action="store_false", default=True, help="skip plugin deployment")
ap.add_argument("-no-strip", dest="strip", action="store_false", default=True, help="don't run 'strip' on the binaries")
ap.add_argument("-sign", dest="sign", action="store_true", default=False, help="sign .app bundle with codesign tool")
ap.add_argument("-dmg", nargs="?", const="", metavar="basename", help="create a .dmg disk image; if basename is not specified, a camel-cased version of the app name is used")
ap.add_argument("-fancy", nargs=1, metavar="plist", default=[], help="make a fancy looking disk image using the given plist file with instructions; requires -dmg to work")
ap.add_argument("-add-qt-tr", nargs=1, metavar="languages", default=[], help="add Qt translation files to the bundle's resources; the language list must be separated with commas, not with whitespace")
ap.add_argument("-translations-dir", nargs=1, metavar="path", default=None, help="Path to Qt's translation files")
ap.add_argument("-add-resources", nargs="+", metavar="path", default=[], help="list of additional files or folders to be copied into the bundle's resources; must be the last argument")
ap.add_argument("-volname", nargs=1, metavar="volname", default=[], help="custom volume name for dmg")
config = ap.parse_args()
verbose = config.verbose[0]
# ------------------------------------------------
app_bundle = config.app_bundle[0]
if not os.path.exists(app_bundle):
if verbose >= 1:
sys.stderr.write("Error: Could not find app bundle \"%s\"\n" % (app_bundle))
sys.exit(1)
app_bundle_name = os.path.splitext(os.path.basename(app_bundle))[0]
# ------------------------------------------------
translations_dir = None
if config.translations_dir and config.translations_dir[0]:
if os.path.exists(config.translations_dir[0]):
translations_dir = config.translations_dir[0]
else:
if verbose >= 1:
sys.stderr.write("Error: Could not find translation dir \"%s\"\n" % (translations_dir))
sys.exit(1)
# ------------------------------------------------
for p in config.add_resources:
if verbose >= 3:
print("Checking for \"%s\"..." % p)
if not os.path.exists(p):
if verbose >= 1:
sys.stderr.write("Error: Could not find additional resource file \"%s\"\n" % (p))
sys.exit(1)
# ------------------------------------------------
if len(config.fancy) == 1:
if verbose >= 3:
print("Fancy: Importing plistlib...")
try:
import plistlib
except ImportError:
if verbose >= 1:
sys.stderr.write("Error: Could not import plistlib which is required for fancy disk images.\n")
sys.exit(1)
p = config.fancy[0]
if verbose >= 3:
print("Fancy: Loading \"%s\"..." % p)
if not os.path.exists(p):
if verbose >= 1:
sys.stderr.write("Error: Could not find fancy disk image plist at \"%s\"\n" % (p))
sys.exit(1)
try:
fancy = plistlib.readPlist(p)
except:
if verbose >= 1:
sys.stderr.write("Error: Could not parse fancy disk image plist at \"%s\"\n" % (p))
sys.exit(1)
try:
assert "window_bounds" not in fancy or (isinstance(fancy["window_bounds"], list) and len(fancy["window_bounds"]) == 4)
assert "background_picture" not in fancy or isinstance(fancy["background_picture"], str)
assert "icon_size" not in fancy or isinstance(fancy["icon_size"], int)
assert "applications_symlink" not in fancy or isinstance(fancy["applications_symlink"], bool)
if "items_position" in fancy:
assert isinstance(fancy["items_position"], dict)
for key, value in fancy["items_position"].items():
assert isinstance(value, list) and len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int)
except:
if verbose >= 1:
sys.stderr.write("Error: Bad format of fancy disk image plist at \"%s\"\n" % (p))
sys.exit(1)
if "background_picture" in fancy:
bp = fancy["background_picture"]
if verbose >= 3:
print("Fancy: Resolving background picture \"%s\"..." % bp)
if not os.path.exists(bp):
bp = os.path.join(os.path.dirname(p), bp)
if not os.path.exists(bp):
if verbose >= 1:
sys.stderr.write("Error: Could not find background picture at \"%s\" or \"%s\"\n" % (fancy["background_picture"], bp))
sys.exit(1)
else:
fancy["background_picture"] = bp
else:
fancy = None
# ------------------------------------------------
if os.path.exists("dist"):
if verbose >= 2:
print("+ Removing old dist folder +")
shutil.rmtree("dist")
# ------------------------------------------------
if len(config.volname) == 1:
volname = config.volname[0]
else:
volname = app_bundle_name
# ------------------------------------------------
target = os.path.join("dist", "Agrarian-Qt.app")
if verbose >= 2:
print("+ Copying source bundle +")
if verbose >= 3:
print(app_bundle, "->", target)
os.mkdir("dist")
shutil.copytree(app_bundle, target, symlinks=True)
applicationBundle = ApplicationBundleInfo(target)
# ------------------------------------------------
if verbose >= 2:
print("+ Deploying frameworks +")
try:
deploymentInfo = deployFrameworksForAppBundle(applicationBundle, config.strip, verbose)
if deploymentInfo.qtPath is None:
deploymentInfo.qtPath = os.getenv("QTDIR", None)
if deploymentInfo.qtPath is None:
if verbose >= 1:
sys.stderr.write("Warning: Could not detect Qt's path, skipping plugin deployment!\n")
config.plugins = False
except RuntimeError as e:
if verbose >= 1:
sys.stderr.write("Error: %s\n" % str(e))
sys.exit(1)
# ------------------------------------------------
if config.plugins:
if verbose >= 2:
print("+ Deploying plugins +")
try:
deployPlugins(applicationBundle, deploymentInfo, config.strip, verbose)
except RuntimeError as e:
if verbose >= 1:
sys.stderr.write("Error: %s\n" % str(e))
sys.exit(1)
# ------------------------------------------------
if len(config.add_qt_tr) == 0:
add_qt_tr = []
else:
if translations_dir is not None:
qt_tr_dir = translations_dir
else:
if deploymentInfo.qtPath is not None:
qt_tr_dir = os.path.join(deploymentInfo.qtPath, "translations")
else:
sys.stderr.write("Error: Could not find Qt translation path\n")
sys.exit(1)
add_qt_tr = ["qt_%s.qm" % lng for lng in config.add_qt_tr[0].split(",")]
for lng_file in add_qt_tr:
p = os.path.join(qt_tr_dir, lng_file)
if verbose >= 3:
print("Checking for \"%s\"..." % p)
if not os.path.exists(p):
if verbose >= 1:
sys.stderr.write("Error: Could not find Qt translation file \"%s\"\n" % (lng_file))
sys.exit(1)
# ------------------------------------------------
if verbose >= 2:
print("+ Installing qt.conf +")
with open(os.path.join(applicationBundle.resourcesPath, "qt.conf"), "wb") as f:
f.write(qt_conf.encode())
# ------------------------------------------------
if len(add_qt_tr) > 0 and verbose >= 2:
print("+ Adding Qt translations +")
for lng_file in add_qt_tr:
if verbose >= 3:
print(os.path.join(qt_tr_dir, lng_file), "->", os.path.join(applicationBundle.resourcesPath, lng_file))
shutil.copy2(os.path.join(qt_tr_dir, lng_file), os.path.join(applicationBundle.resourcesPath, lng_file))
# ------------------------------------------------
if len(config.add_resources) > 0 and verbose >= 2:
print("+ Adding additional resources +")
for p in config.add_resources:
t = os.path.join(applicationBundle.resourcesPath, os.path.basename(p))
if verbose >= 3:
print(p, "->", t)
if os.path.isdir(p):
shutil.copytree(p, t, symlinks=True)
else:
shutil.copy2(p, t)
# ------------------------------------------------
if config.sign and 'CODESIGNARGS' not in os.environ:
print("You must set the CODESIGNARGS environment variable. Skipping signing.")
elif config.sign:
if verbose >= 1:
print("Code-signing app bundle %s"%(target,))
subprocess.check_call("codesign --force %s %s"%(os.environ['CODESIGNARGS'], target), shell=True)
# ------------------------------------------------
if config.dmg is not None:
def runHDIUtil(verb, image_basename, **kwargs):
hdiutil_args = ["hdiutil", verb, image_basename + ".dmg"]
if "capture_stdout" in kwargs:
del kwargs["capture_stdout"]
run = subprocess.check_output
else:
if verbose < 2:
hdiutil_args.append("-quiet")
elif verbose >= 3:
hdiutil_args.append("-verbose")
run = subprocess.check_call
for key, value in kwargs.items():
hdiutil_args.append("-" + key)
if not value is True:
hdiutil_args.append(str(value))
return run(hdiutil_args, universal_newlines=True)
if verbose >= 2:
if fancy is None:
print("+ Creating .dmg disk image +")
else:
print("+ Preparing .dmg disk image +")
if config.dmg != "":
dmg_name = config.dmg
else:
spl = app_bundle_name.split(" ")
dmg_name = spl[0] + "".join(p.capitalize() for p in spl[1:])
if fancy is None:
try:
runHDIUtil("create", dmg_name, srcfolder="dist", format="UDBZ", volname=volname, ov=True)
except subprocess.CalledProcessError as e:
sys.exit(e.returncode)
else:
if verbose >= 3:
print("Determining size of \"dist\"...")
size = 0
for path, dirs, files in os.walk("dist"):
for file in files:
size += os.path.getsize(os.path.join(path, file))
size += int(size * 0.15)
if verbose >= 3:
print("Creating temp image for modification...")
try:
runHDIUtil("create", dmg_name + ".temp", srcfolder="dist", format="UDRW", size=size, volname=volname, ov=True)
except subprocess.CalledProcessError as e:
sys.exit(e.returncode)
if verbose >= 3:
print("Attaching temp image...")
try:
output = runHDIUtil("attach", dmg_name + ".temp", readwrite=True, noverify=True, noautoopen=True, capture_stdout=True)
except subprocess.CalledProcessError as e:
sys.exit(e.returncode)
m = re.search("/Volumes/(.+$)", output)
disk_root = m.group(0)
disk_name = m.group(1)
if verbose >= 2:
print("+ Applying fancy settings +")
if "background_picture" in fancy:
bg_path = os.path.join(disk_root, ".background", os.path.basename(fancy["background_picture"]))
os.mkdir(os.path.dirname(bg_path))
if verbose >= 3:
print(fancy["background_picture"], "->", bg_path)
shutil.copy2(fancy["background_picture"], bg_path)
else:
bg_path = None
if fancy.get("applications_symlink", False):
os.symlink("/Applications", os.path.join(disk_root, "Applications"))
# The Python appscript package broke with OSX 10.8 and isn't being fixed.
# So we now build up an AppleScript string and use the osascript command
# to make the .dmg file pretty:
appscript = Template( """
on run argv
tell application "Finder"
tell disk "$disk"
open
set current view of container window to icon view
set toolbar visible of container window to false
set statusbar visible of container window to false
set the bounds of container window to {$window_bounds}
set theViewOptions to the icon view options of container window
set arrangement of theViewOptions to not arranged
set icon size of theViewOptions to $icon_size
$background_commands
$items_positions
close -- close/reopen works around a bug...
open
update without registering applications
delay 5
eject
end tell
end tell
end run
""")
itemscript = Template('set position of item "${item}" of container window to {${position}}')
items_positions = []
if "items_position" in fancy:
for name, position in fancy["items_position"].items():
params = { "item" : name, "position" : ",".join([str(p) for p in position]) }
items_positions.append(itemscript.substitute(params))
params = {
"disk" : volname,
"window_bounds" : "300,300,800,620",
"icon_size" : "96",
"background_commands" : "",
"items_positions" : "\n ".join(items_positions)
}
if "window_bounds" in fancy:
params["window_bounds"] = ",".join([str(p) for p in fancy["window_bounds"]])
if "icon_size" in fancy:
params["icon_size"] = str(fancy["icon_size"])
if bg_path is not None:
# Set background file, then call SetFile to make it invisible.
# (note: making it invisible first makes set background picture fail)
bgscript = Template("""set background picture of theViewOptions to file ".background:$bgpic"
do shell script "SetFile -a V /Volumes/$disk/.background/$bgpic" """)
params["background_commands"] = bgscript.substitute({"bgpic" : os.path.basename(bg_path), "disk" : params["disk"]})
s = appscript.substitute(params)
if verbose >= 2:
print("Running AppleScript:")
print(s)
p = subprocess.Popen(['osascript', '-'], stdin=subprocess.PIPE)
p.communicate(input=s.encode('utf-8'))
if p.returncode:
print("Error running osascript.")
if verbose >= 2:
print("+ Finalizing .dmg disk image +")
time.sleep(5)
try:
runHDIUtil("convert", dmg_name + ".temp", format="UDBZ", o=dmg_name + ".dmg", ov=True)
except subprocess.CalledProcessError as e:
sys.exit(e.returncode)
os.unlink(dmg_name + ".temp.dmg")
# ------------------------------------------------
if verbose >= 2:
print("+ Done +")
sys.exit(0)
+5
View File
@@ -0,0 +1,5 @@
### Qos ###
This is a Linux bash script that will set up tc to limit the outgoing bandwidth for connections to the Bitcoin network. It limits outbound TCP traffic with a source or destination port of 51336, but not if the destination IP is within a LAN (defined as 192.168.x.x).
This means one can have an always-on agrariand instance running, and another local agrariand/agrarian-qt instance which connects to this node and receives blocks from it.
+41
View File
@@ -0,0 +1,41 @@
#network interface on which to limit traffic
IF="eth0"
#limit of the network interface in question
LINKCEIL="1gbit"
#limit outbound Bitcoin protocol traffic to this rate
LIMIT="160kbit"
#defines the address space for which you wish to disable rate limiting
LOCALNET="192.168.0.0/16"
#delete existing rules
tc qdisc del dev ${IF} root
#add root class
tc qdisc add dev ${IF} root handle 1: htb default 10
#add parent class
tc class add dev ${IF} parent 1: classid 1:1 htb rate ${LINKCEIL} ceil ${LINKCEIL}
#add our two classes. one unlimited, another limited
tc class add dev ${IF} parent 1:1 classid 1:10 htb rate ${LINKCEIL} ceil ${LINKCEIL} prio 0
tc class add dev ${IF} parent 1:1 classid 1:11 htb rate ${LIMIT} ceil ${LIMIT} prio 1
#add handles to our classes so packets marked with <x> go into the class with "... handle <x> fw ..."
tc filter add dev ${IF} parent 1: protocol ip prio 1 handle 1 fw classid 1:10
tc filter add dev ${IF} parent 1: protocol ip prio 2 handle 2 fw classid 1:11
#delete any existing rules
#disable for now
#ret=0
#while [ $ret -eq 0 ]; do
# iptables -t mangle -D OUTPUT 1
# ret=$?
#done
#limit outgoing traffic to and from port 51336. but not when dealing with a host on the local network
# (defined by $LOCALNET)
# --set-mark marks packages matching these criteria with the number "2"
# these packages are filtered by the tc filter with "handle 2"
# this filter sends the packages into the 1:11 class, and this class is limited to ${LIMIT}
iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 51336 ! -d ${LOCALNET} -j MARK --set-mark 0x2
iptables -t mangle -A OUTPUT -p tcp -m tcp --sport 51336 ! -d ${LOCALNET} -j MARK --set-mark 0x2
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env python
# Helpful little script that spits out a comma-separated list of
# language codes for Qt icons that should be included
# in binary bitcoin distributions
import glob
import os
import re
import sys
if len(sys.argv) != 3:
sys.exit("Usage: %s $QTDIR/translations $BITCOINDIR/src/qt/locale"%sys.argv[0])
d1 = sys.argv[1]
d2 = sys.argv[2]
l1 = set([ re.search(r'qt_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d1, 'qt_*.qm')) ])
l2 = set([ re.search(r'bitcoin_(.*).qm', f).group(1) for f in glob.glob(os.path.join(d2, 'bitcoin_*.qm')) ])
print ",".join(sorted(l1.intersection(l2)))
+185
View File
@@ -0,0 +1,185 @@
RPM Spec File Notes
-------------------
The RPM spec file provided here is for Bitcoin-Core 0.12.0 and builds on CentOS
7 with either the CentOS provided OpenSSL library or with LibreSSL as packaged
at [LibreLAMP.com](https://librelamp.com/). It should hopefully not be too
difficult to port the RPM spec file to most RPM based Linux distributions.
When porting the spec file to build for a particular distribution, there are
some important notes.
## Sources
It is considered good form for all sources to reference a URL where the source
can be downloaded.
Sources 0-9 should be reserved for source code tarballs. `Source0` should
reference the release tarball available from https://bitcoin.org/bin/ and
`Source1` should reference the BerkeleyDB source.
Sources 10-99 are for source files that are maintained in the
[Bitcoin git repository](https://github.com/bitcoin/bitcoin) but are not part of
the release tarball. Most of these will reside in the `contrib` sub-directory.
Sources 10-19 should be reserved for miscellaneous configuration files.
Currently only `Source10` is used, for the example `bitcoin.conf` file.
Sources 20-29 should be reserved for man pages. Currently only `Source20`
through `Source23` are used.
Sources 30-39 should be reserved for SELinux related files. Currently only
`Source30` through `Source32` are used. Until those files are in a tagged
release, the full URL specified in the RPM spec file will not work. You can get
them from the git repository where you retrieved this file.
Sources 100+ are for files that are not source tarballs and are not maintained
in the bitcoin git repository. At present only an SVG version of the Bitcoin
icon is used.
## Patches
In general, patches should be avoided. When a packager feels a patch is
necessary, the packager should bring the problem to the attention of the bitcoin
developers so that an official fix to the issue can make it into the next
release.
### Patch0 bitcoin-0.12.0-libressl.patch
This patch is only needed if building against LibreSSL. LibreSSL is not the
standard TLS library on most Linux distributions. The patch will likely not be
needed when 0.12.1 is released, a proper fix is already in the Bitcoin git
master branch.
## BuildRequires
The packages specified in the `BuildRequires` are specified according to the
package naming convention currently used in CentOS 7 and EPEL for CentOS 7. You
may need to change some of the package names for other distributions. This is
most likely to be the case with the Qt packages.
## BerkeleyDB
The `build-unix.md` file recommends building against BerkeleyDB 4.8.30. Even if
that is the version your Linux distribution ships with, it probably is a good
idea to build Bitcoin Core against a static version of that library compiled
according to the instructions in the `build-unix.md` file so that any changes
the distribution may make in the future will not result in a problem for users.
The problem that can exist, clients built against different versions of
BerkeleyDB may not be able read each other's `wallet.dat` file which can make it
difficult for a user to recover from backup in the event of a system failure.
## Graphical User Interface and Qt Version
The RPM spec file will by default build the GUI client linked against the Qt5
libraries. If you wish instead to link against the Qt4 libraries you need to
pass the switch `-D '_use_qt4 1'` at build time to the `rpmbuild` or `mock`
command used to build the packages.
If you would prefer not to build the GUI at all, you can pass the switch
`-D '_no_gui 1'` to the `rpmbuild` or `mock` build command.
## Desktop and KDE Files
The desktop and KDE meta files are created in the spec file itself with the
`cat` command. This is done to allow easy distribution specific changes without
needing to use any patches. A specific timestamp is given to the files so that
it does not they do not appear to have been updated every time the package is
built. If you do make changes to them, you probably should update timestamp
assigned to them in the `touch` command that specifies the timestamp.
## SVG, PNG, and XPM Icons
The `bitcoin.svg` file is from the source listed as `Source100`. It is used as
the source for the PNG and XPM files. The generated PNG and XPM files are given
the same timestamp as the source SVG file as a means of indicating they are
derived from it.
## Systemd
This spec file assumes the target distribution uses systemd. That really only
matters for the `bitcoin-server` package. At this point, most RPM based
distributions that still receive vendor updates do in fact use systemd.
The files to control the service are created in the RPM spec file itself using
the `cat` command. This is done to make it easy to modify for other
distributions that may implement things differently without needing to patch
source. A specific timestamp is given to the files so that they do not appear
to have been updated every time the package is built. If you do make changes to
them, you probably should update the timestamp assigned to them in the `touch`
command that specifies the timestamp.
## SELinux
The `bitcoin-server` package should have SELinux support. How to properly do
that *may* vary by distribution and version of distribution.
The SELinux stuff in this RPM spec file *should* be correct for CentOS, RHEL,
and Fedora but it would be a good idea to review it before building the package
on other distributions.
## Tests
The `%check` section takes a very long time to run. If your build system has a
time limit for package build, you may need to make an exception for this
package. On CentOS 7 the `%check` section completes successfully with both
OpenSSL and LibreSSL, a failure really does mean something is wrong.
## LibreSSL Build Notes
To build against LibreSSL you will need to pass the switch
`-D '_use_libressl 1'` to the `rpmbuild` or `mock` command or the spec file will
want the OpenSSL development files.
### LibreSSL and Boost
LibreSSL (and some newer builds of OpenSSL) do not have support for SSLv3. This
can cause issues with the Boost package if the Boost package has not been
patched accordingly. On those distributions, you will either need to build
Bitcoin-Core against OpenSSL or use a patched version of Boost in the build
system.
As SSLv3 is no longer safe, distributions that have not patched Boost to work
with TLS libraries that do not support SSLv3 should have bug reports filed
against the Boost package. This bug report has already been filed for RHEL 7 but
it may need to be filed for other distributions.
A patch for Boost: https://github.com/boostorg/asio/pull/23/files
## ZeroMQ
At this time, this RPM spec file does not support the ZeroMQ build options. A
suitable version of ZeroMQ is not available for the platform this spec file was
developed on (CentOS 7).
## Legacy Credit
This RPM spec file is largely based upon the work of Michael Hampton at
[Ringing Liberty](https://www.ringingliberty.com/bitcoin/). He has been
packaging Bitcoin for Fedora at least since 2012.
Most of the differences between his packaging and this package are stylistic in
nature. The major differences:
1. He builds from a github tagged release rather than a release tarball. This
should not result in different source code.
2. He does not build BerkeleyDB but instead uses the BerkeleyDB provided by the
Linux distribution. For the distributions he packages for, they currently all
use the same version of BerkeleyDB so that difference is *probably* just
academic.
3. As of his 10.11.2 package he did not allow for building against LibreSSL,
specifying a build without the Qt GUI, or specifying which version of the Qt
libraries to use.
4. I renamed the `bitcoin` package that contains the Qt GUI to `bitcoin-core` as
that appears to be how the general population refers to it, in contrast to
`bitcoin-xt` or `bitcoin-classic`. I wanted to make sure the general population
knows what they are getting when installing the GUI package.
As far as minor differences, I generally prefer to assign the file permissions
in the `%files` portion of an RPM spec file rather than specifying the
permissions of a file during `%install` and other minor things like that
are largely just cosmetic.
+8
View File
@@ -0,0 +1,8 @@
/usr/bin/agrarian-cli -- gen_context(system_u:object_r:agrarian_exec_t,s0)
/usr/sbin/agrariand -- gen_context(system_u:object_r:agrarian_exec_t,s0)
/usr/lib(64)?/agrarian/agrariand -- gen_context(system_u:object_r:agrarian_exec_t,s0)
/etc/agrarian(/.*)? gen_context(system_u:object_r:agrarian_conf_t,s0)
/var/lib/agrarian(/.*)? gen_context(system_u:object_r:agrarian_var_lib_t,s0)
(/var)?/run/agrariand(/.*)? gen_context(system_u:object_r:agrarian_var_run_t,s0)
+157
View File
@@ -0,0 +1,157 @@
## <summary>policy for agrarian</summary>
########################################
## <summary>
## Transition to agrarian.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed to transition.
## </summary>
## </param>
#
interface(`agrarian_domtrans',`
gen_require(`
type agrarian_t, agrarian_exec_t;
')
corecmd_search_bin($1)
domtrans_pattern($1, agrarian_exec_t, agrarian_t)
')
########################################
## <summary>
## Execute agrarian server in the agrarian domain.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`agrarian_initrc_domtrans',`
gen_require(`
type agrarian_initrc_exec_t;
')
init_labeled_script_domtrans($1, agrarian_initrc_exec_t)
')
########################################
## <summary>
## Search agrarian lib directories.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`agrarian_search_lib',`
gen_require(`
type agrarian_var_lib_t;
')
allow $1 agrarian_var_lib_t:dir search_dir_perms;
files_search_var_lib($1)
')
########################################
## <summary>
## Read agrarian lib files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`agrarian_read_lib_files',`
gen_require(`
type agrarian_var_lib_t;
')
files_search_var_lib($1)
read_files_pattern($1, agrarian_var_lib_t, agrarian_var_lib_t)
')
########################################
## <summary>
## Manage agrarian lib files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`agrarian_manage_lib_files',`
gen_require(`
type agrarian_var_lib_t;
')
files_search_var_lib($1)
manage_files_pattern($1, agrarian_var_lib_t, agrarian_var_lib_t)
')
########################################
## <summary>
## Manage agrarian lib directories.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
#
interface(`agrarian_manage_lib_dirs',`
gen_require(`
type agrarian_var_lib_t;
')
files_search_var_lib($1)
manage_dirs_pattern($1, agrarian_var_lib_t, agrarian_var_lib_t)
')
########################################
## <summary>
## All of the rules required to administrate
## a agrarian environment
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
## <param name="role">
## <summary>
## Role allowed access.
## </summary>
## </param>
## <rolecap/>
#
interface(`agrarian_admin',`
gen_require(`
type agrarian_t;
type agrarian_initrc_exec_t;
type agrarian_var_lib_t;
')
allow $1 agrarian_t:process { ptrace signal_perms };
ps_process_pattern($1, agrarian_t)
agrarian_initrc_domtrans($1)
domain_system_change_exemption($1)
role_transition $2 agrarian_initrc_exec_t system_r;
allow $2 system_r;
files_search_var_lib($1)
admin_pattern($1, agrarian_var_lib_t)
')
+442
View File
@@ -0,0 +1,442 @@
%define bdbv 4.8.30
%global selinux_variants mls strict targeted
%if 0%{?_no_gui:1}
%define _buildqt 0
%define buildargs --with-gui=no
%else
%define _buildqt 1
%if 0%{?_use_qt4}
%define buildargs --with-qrencode --with-gui=qt4
%else
%define buildargs --with-qrencode --with-gui=qt5
%endif
%endif
Name: agrarian
Version: 0.12.0
Release: 2%{?dist}
Summary: Peer to Peer Cryptographic Currency
Group: Applications/System
License: MIT
URL: https://agrarian.org/
Source0: https://agrarian.org/bin/agrarian-core-%{version}/agrarian-%{version}.tar.gz
Source1: http://download.oracle.com/berkeley-db/db-%{bdbv}.NC.tar.gz
Source10: https://raw.githubusercontent.com/agrarian-project/agrarian/v%{version}/contrib/debian/examples/agrarian.conf
#man pages
Source20: https://raw.githubusercontent.com/agrarian-project/agrarian/v%{version}/doc/man/agrariand.1
Source21: https://raw.githubusercontent.com/agrarian-project/agrarian/v%{version}/doc/man/agrarian-cli.1
Source22: https://raw.githubusercontent.com/agrarian-project/agrarian/v%{version}/doc/man/agrarian-qt.1
#selinux
Source30: https://raw.githubusercontent.com/agrarian-project/agrarian/v%{version}/contrib/rpm/agrarian.te
# Source31 - what about agrarian-tx and bench_agrarian ???
Source31: https://raw.githubusercontent.com/agrarian-project/agrarian/v%{version}/contrib/rpm/agrarian.fc
Source32: https://raw.githubusercontent.com/agrarian-project/agrarian/v%{version}/contrib/rpm/agrarian.if
Source100: https://upload.wikimedia.org/wikipedia/commons/4/46/Bitcoin.svg
%if 0%{?_use_libressl:1}
BuildRequires: libressl-devel
%else
BuildRequires: openssl-devel
%endif
BuildRequires: boost-devel
BuildRequires: miniupnpc-devel
BuildRequires: autoconf automake libtool
BuildRequires: libevent-devel
Patch0: agrarian-0.12.0-libressl.patch
%description
Bitcoin is a digital cryptographic currency that uses peer-to-peer technology to
operate with no central authority or banks; managing transactions and the
issuing of agrarians is carried out collectively by the network.
%if %{_buildqt}
%package core
Summary: Peer to Peer Cryptographic Currency
Group: Applications/System
Obsoletes: %{name} < %{version}-%{release}
Provides: %{name} = %{version}-%{release}
%if 0%{?_use_qt4}
BuildRequires: qt-devel
%else
BuildRequires: qt5-qtbase-devel
# for /usr/bin/lrelease-qt5
BuildRequires: qt5-linguist
%endif
BuildRequires: protobuf-devel
BuildRequires: qrencode-devel
BuildRequires: %{_bindir}/desktop-file-validate
# for icon generation from SVG
BuildRequires: %{_bindir}/inkscape
BuildRequires: %{_bindir}/convert
%description core
Bitcoin is a digital cryptographic currency that uses peer-to-peer technology to
operate with no central authority or banks; managing transactions and the
issuing of agrarians is carried out collectively by the network.
This package contains the Qt based graphical client and node. If you are looking
to run a Bitcoin wallet, this is probably the package you want.
%endif
%package libs
Summary: Bitcoin shared libraries
Group: System Environment/Libraries
%description libs
This package provides the agrarianconsensus shared libraries. These libraries
may be used by third party software to provide consensus verification
functionality.
Unless you know need this package, you probably do not.
%package devel
Summary: Development files for agrarian
Group: Development/Libraries
Requires: %{name}-libs = %{version}-%{release}
%description devel
This package contains the header files and static library for the
agrarianconsensus shared library. If you are developing or compiling software
that wants to link against that library, then you need this package installed.
Most people do not need this package installed.
%package server
Summary: The agrarian daemon
Group: System Environment/Daemons
Requires: agrarian-utils = %{version}-%{release}
Requires: selinux-policy policycoreutils-python
Requires(pre): shadow-utils
Requires(post): %{_sbindir}/semodule %{_sbindir}/restorecon %{_sbindir}/fixfiles %{_sbindir}/sestatus
Requires(postun): %{_sbindir}/semodule %{_sbindir}/restorecon %{_sbindir}/fixfiles %{_sbindir}/sestatus
BuildRequires: systemd
BuildRequires: checkpolicy
BuildRequires: %{_datadir}/selinux/devel/Makefile
%description server
This package provides a stand-alone agrarian-core daemon. For most users, this
package is only needed if they need a full-node without the graphical client.
Some third party wallet software will want this package to provide the actual
agrarian-core node they use to connect to the network.
If you use the graphical agrarian-core client then you almost certainly do not
need this package.
%package utils
Summary: Bitcoin utilities
Group: Applications/System
%description utils
This package provides several command line utilities for interacting with a
agrarian-core daemon.
The agrarian-cli utility allows you to communicate and control a agrarian daemon
over RPC, the agrarian-tx utility allows you to create a custom transaction, and
the bench_agrarian utility can be used to perform some benchmarks.
This package contains utilities needed by the agrarian-server package.
%prep
%setup -q
%patch0 -p1 -b .libressl
cp -p %{SOURCE10} ./agrarian.conf.example
tar -zxf %{SOURCE1}
cp -p db-%{bdbv}.NC/LICENSE ./db-%{bdbv}.NC-LICENSE
mkdir db4 SELinux
cp -p %{SOURCE30} %{SOURCE31} %{SOURCE32} SELinux/
%build
CWD=`pwd`
cd db-%{bdbv}.NC/build_unix/
../dist/configure --enable-cxx --disable-shared --with-pic --prefix=${CWD}/db4
make install
cd ../..
./autogen.sh
%configure LDFLAGS="-L${CWD}/db4/lib/" CPPFLAGS="-I${CWD}/db4/include/" --with-miniupnpc --enable-glibc-back-compat %{buildargs}
make %{?_smp_mflags}
pushd SELinux
for selinuxvariant in %{selinux_variants}; do
make NAME=${selinuxvariant} -f %{_datadir}/selinux/devel/Makefile
mv agrarian.pp agrarian.pp.${selinuxvariant}
make NAME=${selinuxvariant} -f %{_datadir}/selinux/devel/Makefile clean
done
popd
%install
make install DESTDIR=%{buildroot}
mkdir -p -m755 %{buildroot}%{_sbindir}
mv %{buildroot}%{_bindir}/agrariand %{buildroot}%{_sbindir}/agrariand
# systemd stuff
mkdir -p %{buildroot}%{_tmpfilesdir}
cat <<EOF > %{buildroot}%{_tmpfilesdir}/agrarian.conf
d /run/agrariand 0750 agrarian agrarian -
EOF
touch -a -m -t 201504280000 %{buildroot}%{_tmpfilesdir}/agrarian.conf
mkdir -p %{buildroot}%{_sysconfdir}/sysconfig
cat <<EOF > %{buildroot}%{_sysconfdir}/sysconfig/agrarian
# Provide options to the agrarian daemon here, for example
# OPTIONS="-testnet -disable-wallet"
OPTIONS=""
# System service defaults.
# Don't change these unless you know what you're doing.
CONFIG_FILE="%{_sysconfdir}/agrarian/agrarian.conf"
DATA_DIR="%{_localstatedir}/lib/agrarian"
PID_FILE="/run/agrariand/agrariand.pid"
EOF
touch -a -m -t 201504280000 %{buildroot}%{_sysconfdir}/sysconfig/agrarian
mkdir -p %{buildroot}%{_unitdir}
cat <<EOF > %{buildroot}%{_unitdir}/agrarian.service
[Unit]
Description=Bitcoin daemon
After=syslog.target network.target
[Service]
Type=forking
ExecStart=%{_sbindir}/agrariand -daemon -conf=\${CONFIG_FILE} -datadir=\${DATA_DIR} -pid=\${PID_FILE} \$OPTIONS
EnvironmentFile=%{_sysconfdir}/sysconfig/agrarian
User=agrarian
Group=agrarian
Restart=on-failure
PrivateTmp=true
TimeoutStopSec=120
TimeoutStartSec=60
StartLimitInterval=240
StartLimitBurst=5
[Install]
WantedBy=multi-user.target
EOF
touch -a -m -t 201504280000 %{buildroot}%{_unitdir}/agrarian.service
#end systemd stuff
mkdir %{buildroot}%{_sysconfdir}/agrarian
mkdir -p %{buildroot}%{_localstatedir}/lib/agrarian
#SELinux
for selinuxvariant in %{selinux_variants}; do
install -d %{buildroot}%{_datadir}/selinux/${selinuxvariant}
install -p -m 644 SELinux/agrarian.pp.${selinuxvariant} %{buildroot}%{_datadir}/selinux/${selinuxvariant}/agrarian.pp
done
%if %{_buildqt}
# qt icons
install -D -p share/pixmaps/agrarian.ico %{buildroot}%{_datadir}/pixmaps/agrarian.ico
install -p share/pixmaps/nsis-header.bmp %{buildroot}%{_datadir}/pixmaps/
install -p share/pixmaps/nsis-wizard.bmp %{buildroot}%{_datadir}/pixmaps/
install -p %{SOURCE100} %{buildroot}%{_datadir}/pixmaps/agrarian.svg
%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/agrarian16.png -w16 -h16
%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/agrarian32.png -w32 -h32
%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/agrarian64.png -w64 -h64
%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/agrarian128.png -w128 -h128
%{_bindir}/inkscape %{SOURCE100} --export-png=%{buildroot}%{_datadir}/pixmaps/agrarian256.png -w256 -h256
%{_bindir}/convert -resize 16x16 %{buildroot}%{_datadir}/pixmaps/agrarian256.png %{buildroot}%{_datadir}/pixmaps/agrarian16.xpm
%{_bindir}/convert -resize 32x32 %{buildroot}%{_datadir}/pixmaps/agrarian256.png %{buildroot}%{_datadir}/pixmaps/agrarian32.xpm
%{_bindir}/convert -resize 64x64 %{buildroot}%{_datadir}/pixmaps/agrarian256.png %{buildroot}%{_datadir}/pixmaps/agrarian64.xpm
%{_bindir}/convert -resize 128x128 %{buildroot}%{_datadir}/pixmaps/agrarian256.png %{buildroot}%{_datadir}/pixmaps/agrarian128.xpm
%{_bindir}/convert %{buildroot}%{_datadir}/pixmaps/agrarian256.png %{buildroot}%{_datadir}/pixmaps/agrarian256.xpm
touch %{buildroot}%{_datadir}/pixmaps/*.png -r %{SOURCE100}
touch %{buildroot}%{_datadir}/pixmaps/*.xpm -r %{SOURCE100}
# Desktop File - change the touch timestamp if modifying
mkdir -p %{buildroot}%{_datadir}/applications
cat <<EOF > %{buildroot}%{_datadir}/applications/agrarian-core.desktop
[Desktop Entry]
Encoding=UTF-8
Name=Bitcoin
Comment=Bitcoin P2P Cryptocurrency
Comment[fr]=Bitcoin, monnaie virtuelle cryptographique pair à pair
Comment[tr]=Bitcoin, eşten eşe kriptografik sanal para birimi
Exec=agrarian-qt %u
Terminal=false
Type=Application
Icon=agrarian128
MimeType=x-scheme-handler/agrarian;
Categories=Office;Finance;
EOF
# change touch date when modifying desktop
touch -a -m -t 201511100546 %{buildroot}%{_datadir}/applications/agrarian-core.desktop
%{_bindir}/desktop-file-validate %{buildroot}%{_datadir}/applications/agrarian-core.desktop
# KDE protocol - change the touch timestamp if modifying
mkdir -p %{buildroot}%{_datadir}/kde4/services
cat <<EOF > %{buildroot}%{_datadir}/kde4/services/agrarian-core.protocol
[Protocol]
exec=agrarian-qt '%u'
protocol=agrarian
input=none
output=none
helper=true
listing=
reading=false
writing=false
makedir=false
deleting=false
EOF
# change touch date when modifying protocol
touch -a -m -t 201511100546 %{buildroot}%{_datadir}/kde4/services/agrarian-core.protocol
%endif
# man pages
install -D -p %{SOURCE20} %{buildroot}%{_mandir}/man1/agrariand.1
install -p %{SOURCE21} %{buildroot}%{_mandir}/man1/agrarian-cli.1
%if %{_buildqt}
install -p %{SOURCE22} %{buildroot}%{_mandir}/man1/agrarian-qt.1
%endif
# nuke these, we do extensive testing of binaries in %%check before packaging
rm -f %{buildroot}%{_bindir}/test_*
%check
make check
srcdir=src test/agrarian-util-test.py
test/functional/test_runner.py --extended
%post libs -p /sbin/ldconfig
%postun libs -p /sbin/ldconfig
%pre server
getent group agrarian >/dev/null || groupadd -r agrarian
getent passwd agrarian >/dev/null ||
useradd -r -g agrarian -d /var/lib/agrarian -s /sbin/nologin \
-c "Bitcoin wallet server" agrarian
exit 0
%post server
%systemd_post agrarian.service
# SELinux
if [ `%{_sbindir}/sestatus |grep -c "disabled"` -eq 0 ]; then
for selinuxvariant in %{selinux_variants}; do
%{_sbindir}/semodule -s ${selinuxvariant} -i %{_datadir}/selinux/${selinuxvariant}/agrarian.pp &> /dev/null || :
done
%{_sbindir}/semanage port -a -t agrarian_port_t -p tcp 8332
%{_sbindir}/semanage port -a -t agrarian_port_t -p tcp 8333
%{_sbindir}/semanage port -a -t agrarian_port_t -p tcp 18332
%{_sbindir}/semanage port -a -t agrarian_port_t -p tcp 18333
%{_sbindir}/semanage port -a -t agrarian_port_t -p tcp 18443
%{_sbindir}/semanage port -a -t agrarian_port_t -p tcp 18444
%{_sbindir}/fixfiles -R agrarian-server restore &> /dev/null || :
%{_sbindir}/restorecon -R %{_localstatedir}/lib/agrarian || :
fi
%posttrans server
%{_bindir}/systemd-tmpfiles --create
%preun server
%systemd_preun agrarian.service
%postun server
%systemd_postun agrarian.service
# SELinux
if [ $1 -eq 0 ]; then
if [ `%{_sbindir}/sestatus |grep -c "disabled"` -eq 0 ]; then
%{_sbindir}/semanage port -d -p tcp 8332
%{_sbindir}/semanage port -d -p tcp 8333
%{_sbindir}/semanage port -d -p tcp 18332
%{_sbindir}/semanage port -d -p tcp 18333
%{_sbindir}/semanage port -d -p tcp 18443
%{_sbindir}/semanage port -d -p tcp 18444
for selinuxvariant in %{selinux_variants}; do
%{_sbindir}/semodule -s ${selinuxvariant} -r agrarian &> /dev/null || :
done
%{_sbindir}/fixfiles -R agrarian-server restore &> /dev/null || :
[ -d %{_localstatedir}/lib/agrarian ] && \
%{_sbindir}/restorecon -R %{_localstatedir}/lib/agrarian &> /dev/null || :
fi
fi
%clean
rm -rf %{buildroot}
%if %{_buildqt}
%files core
%defattr(-,root,root,-)
%license COPYING db-%{bdbv}.NC-LICENSE
%doc COPYING agrarian.conf.example doc/README.md doc/bips.md doc/files.md doc/multiwallet-qt.md doc/reduce-traffic.md doc/release-notes.md doc/tor.md
%attr(0755,root,root) %{_bindir}/agrarian-qt
%attr(0644,root,root) %{_datadir}/applications/agrarian-core.desktop
%attr(0644,root,root) %{_datadir}/kde4/services/agrarian-core.protocol
%attr(0644,root,root) %{_datadir}/pixmaps/*.ico
%attr(0644,root,root) %{_datadir}/pixmaps/*.bmp
%attr(0644,root,root) %{_datadir}/pixmaps/*.svg
%attr(0644,root,root) %{_datadir}/pixmaps/*.png
%attr(0644,root,root) %{_datadir}/pixmaps/*.xpm
%attr(0644,root,root) %{_mandir}/man1/agrarian-qt.1*
%endif
%files libs
%defattr(-,root,root,-)
%license COPYING
%doc COPYING doc/README.md doc/shared-libraries.md
%{_libdir}/lib*.so.*
%files devel
%defattr(-,root,root,-)
%license COPYING
%doc COPYING doc/README.md doc/developer-notes.md doc/shared-libraries.md
%attr(0644,root,root) %{_includedir}/*.h
%{_libdir}/*.so
%{_libdir}/*.a
%{_libdir}/*.la
%attr(0644,root,root) %{_libdir}/pkgconfig/*.pc
%files server
%defattr(-,root,root,-)
%license COPYING db-%{bdbv}.NC-LICENSE
%doc COPYING agrarian.conf.example doc/README.md doc/REST-interface.md doc/bips.md doc/dnsseed-policy.md doc/files.md doc/reduce-traffic.md doc/release-notes.md doc/tor.md
%attr(0755,root,root) %{_sbindir}/agrariand
%attr(0644,root,root) %{_tmpfilesdir}/agrarian.conf
%attr(0644,root,root) %{_unitdir}/agrarian.service
%dir %attr(0750,agrarian,agrarian) %{_sysconfdir}/agrarian
%dir %attr(0750,agrarian,agrarian) %{_localstatedir}/lib/agrarian
%config(noreplace) %attr(0600,root,root) %{_sysconfdir}/sysconfig/agrarian
%attr(0644,root,root) %{_datadir}/selinux/*/*.pp
%attr(0644,root,root) %{_mandir}/man1/agrariand.1*
%files utils
%defattr(-,root,root,-)
%license COPYING
%doc COPYING agrarian.conf.example doc/README.md
%attr(0755,root,root) %{_bindir}/agrarian-cli
%attr(0755,root,root) %{_bindir}/agrarian-tx
%attr(0755,root,root) %{_bindir}/bench_agrarian
%attr(0644,root,root) %{_mandir}/man1/agrarian-cli.1*
%changelog
* Fri Feb 26 2016 Alice Wonder <buildmaster@librelamp.com> - 0.12.0-2
- Rename Qt package from agrarian to agrarian-core
- Make building of the Qt package optional
- When building the Qt package, default to Qt5 but allow building
- against Qt4
- Only run SELinux stuff in post scripts if it is not set to disabled
* Wed Feb 24 2016 Alice Wonder <buildmaster@librelamp.com> - 0.12.0-1
- Initial spec file for 0.12.0 release
# This spec file is written from scratch but a lot of the packaging decisions are directly
# based upon the 0.11.2 package spec file from https://www.ringingliberty.com/agrarian/
+81
View File
@@ -0,0 +1,81 @@
policy_module(agrarian, 1.100.1)
########################################
#
# Declarations
#
type agrarian_t;
type agrarian_exec_t;
init_daemon_domain(agrarian_t, agrarian_exec_t)
permissive agrarian_t;
type agrarian_initrc_exec_t;
init_script_file(agrarian_initrc_exec_t)
type agrarian_conf_t;
files_type(agrarian_conf_t)
type agrarian_var_lib_t;
files_type(agrarian_var_lib_t)
type agrarian_var_run_t;
files_type(agrarian_var_run_t)
type agrarian_port_t;
corenet_port(agrarian_port_t)
########################################
#
# agrarian local policy
#
allow agrarian_t self:process { fork };
allow agrarian_t self:fifo_file rw_fifo_file_perms;
allow agrarian_t self:unix_stream_socket create_stream_socket_perms;
manage_dirs_pattern(agrarian_t, agrarian_conf_t, agrarian_conf_t)
manage_files_pattern(agrarian_t, agrarian_conf_t, agrarian_conf_t)
manage_dirs_pattern(agrarian_t, agrarian_var_lib_t, agrarian_var_lib_t)
manage_files_pattern(agrarian_t, agrarian_var_lib_t, agrarian_var_lib_t)
files_var_lib_filetrans(agrarian_t, agrarian_var_lib_t, { dir file })
manage_dirs_pattern(agrarian_t, agrarian_var_run_t, agrarian_var_run_t)
manage_files_pattern(agrarian_t, agrarian_var_run_t, agrarian_var_run_t)
sysnet_dns_name_resolve(agrarian_t)
corenet_all_recvfrom_unlabeled(agrarian_t)
allow agrarian_t self:tcp_socket create_stream_socket_perms;
corenet_tcp_sendrecv_generic_if(agrarian_t)
corenet_tcp_sendrecv_generic_node(agrarian_t)
corenet_tcp_sendrecv_all_ports(agrarian_t)
corenet_tcp_bind_generic_node(agrarian_t)
gen_require(`
type agrarian_port_t;
')
allow agrarian_t agrarian_port_t:tcp_socket name_bind;
gen_require(`
type agrarian_port_t;
')
allow agrarian_t agrarian_port_t:tcp_socket name_connect;
domain_use_interactive_fds(agrarian_t)
files_read_etc_files(agrarian_t)
miscfiles_read_localization(agrarian_t)
sysnet_dns_name_resolve(agrarian_t)
allow agrarian_t agrarian_exec_t:file execute_no_trans;
allow agrarian_t self:process setsched;
corecmd_exec_ls(agrarian_t)
corenet_tcp_connect_http_port(agrarian_t)
dev_read_urand(agrarian_t)
fs_getattr_xattr_fs(agrarian_t)
kernel_read_system_state(agrarian_t)

Some files were not shown because too many files have changed in this diff Show More