ghidra/gradle/support/fetchDependencies.gradle

573 lines
24 KiB
Groovy

/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*******************************************************************************
* fetchDependencies.gradle *
* *
* Fetches/downloads required dependencies that aren't available in the *
* standard online repositories (eg: maven) and configures a flat *
* directory-style respository that points to them. This should be run *
* immediately after cloning the Ghidra repository before any other gradle *
* tasks are run. *
* *
* usage: from the command line in the main ghidra repository directory, run *
* the following: *
* *
* gradle -I gradle/support/fetchDependencies.gradle init *
* *
* Note: When running the script, files will only be downloaded if *
* necessary (eg: they are not already in the dependencies/downloads/ *
* directory). *
* *
*******************************************************************************/
import java.util.zip.*;
import java.nio.file.*;
import java.security.MessageDigest;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.WildcardFileFilter;
initscript {
repositories { mavenCentral() }
dependencies { classpath 'commons-io:commons-io:2.11.0' }
}
ext.NUM_RETRIES = 3 // # of times to try to download a file before failing
ext.REPO_DIR = ((Script)this).buildscript.getSourceFile().getParentFile().getParentFile().getParentFile()
ext.DEPS_DIR = file("${REPO_DIR}/dependencies")
ext.DOWNLOADS_DIR = file("${DEPS_DIR}/downloads")
ext.FID_DIR = file("${DEPS_DIR}/fidb")
ext.FLAT_REPO_DIR = file("${DEPS_DIR}/flatRepo")
ext.OFFLINE = System.properties["offline"] != null
ext.HIDE_DOWNLOAD_PROGRESS = System.properties["hideDownloadProgress"] != null
ext.createdDirs = [] as Set
file("${REPO_DIR}/Ghidra/application.properties").withReader { reader ->
def ghidraProps = new Properties()
ghidraProps.load(reader)
ext.RELEASE_VERSION = ghidraProps.getProperty('application.version')
}
ext.deps = [
[
name: "java-sarif-2.1-modified.jar",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/lib/java-sarif-2.1-modified.jar",
sha256: "7f736566494756d271aa5e4b1af6c89dc50d074ab1c6374a47df822264226b01",
destination: FLAT_REPO_DIR
],
[
name: "dbgmodel.tlb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/Debugger/dbgmodel.tlb",
sha256: "8cf5f3a2eb81160aa349056a5ca4c2c726b1b6e98bf3097cd4135147163343c7",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "AXMLPrinter2.jar",
url: "https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/android4me/AXMLPrinter2.jar",
sha256: "00ed038eb6abaf6ddec8d202a3ed7a81b521458f4cd459948115cfd02ff59d6d",
destination: FLAT_REPO_DIR
],
[
name: "yajsw-stable-13.12.zip",
url: "https://sourceforge.net/projects/yajsw/files/yajsw/yajsw-stable-13.12/yajsw-stable-13.12.zip",
sha256: "c6fc59815d3800d14ec977926a8afd3f606a0ebd74d2cfd60601677466edeaa2",
destination: file("${DEPS_DIR}/GhidraServer")
],
[
name: "postgresql-15.13.tar.gz",
url: "https://ftp.postgresql.org/pub/source/v15.13/postgresql-15.13.tar.gz",
sha256: "afdc22b0a6e5bec7b65723756b90d44ea911e61b2f7b01c4dc5524ab813b4d89",
destination: file("${DEPS_DIR}/BSim")
],
[
name: "PyDev 9.3.0.zip",
url: "https://sourceforge.net/projects/pydev/files/pydev/PyDev%209.3.0/PyDev%209.3.0.zip",
sha256: "45398edf2adb56078a80bc88a919941578f0c0b363efbdd011bfd158a99b112e",
destination: file("${DEPS_DIR}/GhidraDev")
],
[
name: "cdt-8.6.0.zip",
url: "https://archive.eclipse.org/tools/cdt/releases/8.6/cdt-8.6.0.zip",
sha256: "81b7d19d57c4a3009f4761699a72e8d642b5e1d9251d2bb98df438b1e28f8ba9",
destination: file("${DEPS_DIR}/GhidraDev")
],
[
name: "vs2012_x64.fidb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/FunctionID/vs2012_x64.fidb",
sha256: "d4e98ab3f790b831793218430bba0d8b24a5fbf4da65b0c1ffa8cb0cfbeb0cdc",
destination: FID_DIR
],
[
name: "vs2012_x86.fidb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/FunctionID/vs2012_x86.fidb",
sha256: "a490ed7e2ed21e587459feaeace7036b7ede4ce84e72e10dfd8c57434a6918b6",
destination: FID_DIR
],
[
name: "vs2015_x64.fidb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/FunctionID/vs2015_x64.fidb",
sha256: "e04e9e40f9ecb601c85f4d84ed9bf66b45363be1d1e82c162e4c9902b8cb508f",
destination: FID_DIR
],
[
name: "vs2015_x86.fidb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/FunctionID/vs2015_x86.fidb",
sha256: "b66ee696653e2ed365919deaaef885103120c792e22e79af70d1209d7e1d8644",
destination: FID_DIR
],
[
name: "vs2017_x64.fidb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/FunctionID/vs2017_x64.fidb",
sha256: "d5fa5f697298174fa53d247d3599e6a12884605ad181c7b954e2380ec1f0bd89",
destination: FID_DIR
],
[
name: "vs2017_x86.fidb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/FunctionID/vs2017_x86.fidb",
sha256: "d389cb8d76ff4a59ca35f891b8521c72ad5f0df96e253973a2d21a8614a4cc81",
destination: FID_DIR
],
[
name: "vs2019_x64.fidb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/FunctionID/vs2019_x64.fidb",
sha256: "150007796fc36a4069660ad62449aadaaf3dd11b3864a5ef21e79831c9ce9118",
destination: FID_DIR
],
[
name: "vs2019_x86.fidb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/FunctionID/vs2019_x86.fidb",
sha256: "eb630a36faa586a371eb734dc0bbd8d13ccaef697f3db5872596358f3dd2432a",
destination: FID_DIR
],
[
name: "vsOlder_x64.fidb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/FunctionID/vsOlder_x64.fidb",
sha256: "8c3b51f4660cd27e1a0d610a9f3f2d5fbc833a66ac9ee4393ee2f2481e855866",
destination: FID_DIR
],
[
name: "vsOlder_x86.fidb",
url: "https://github.com/NationalSecurityAgency/ghidra-data/raw/Ghidra_${RELEASE_VERSION}/FunctionID/vsOlder_x86.fidb",
sha256: "98605c6b6b9214a945d844e41c85860d54649a45bca7873ef6991c0e93720787",
destination: FID_DIR
],
[
name: "protobuf-3.20.3-py2.py3-none-any.whl",
url: "https://files.pythonhosted.org/packages/8d/14/619e24a4c70df2901e1f4dbc50a6291eb63a759172558df326347dce1f0d/protobuf-3.20.3-py2.py3-none-any.whl",
sha256: "a7ca6d488aa8ff7f329d4c545b2dbad8ac31464f1d8b1c87ad1346717731e4db",
destination: file("${DEPS_DIR}/Debugger-rmi-trace/")
],
[
name: "psutil-5.9.8.tar.gz",
url: "https://files.pythonhosted.org/packages/90/c7/6dc0a455d111f68ee43f27793971cf03fe29b6ef972042549db29eec39a2/psutil-5.9.8.tar.gz",
sha256: "6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c",
destination: file("${DEPS_DIR}/Debugger-rmi-trace/")
],
[
name: "setuptools-68.0.0-py3-none-any.whl",
url: "https://files.pythonhosted.org/packages/c7/42/be1c7bbdd83e1bfb160c94b9cafd8e25efc7400346cf7ccdbdb452c467fa/setuptools-68.0.0-py3-none-any.whl",
sha256: "11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f",
destination: [file("${DEPS_DIR}/Debugger-rmi-trace/"), file("${DEPS_DIR}/PyGhidra/")]
],
[
name: "wheel-0.37.1-py2.py3-none-any.whl",
url: "https://files.pythonhosted.org/packages/27/d6/003e593296a85fd6ed616ed962795b2f87709c3eee2bca4f6d0fe55c6d00/wheel-0.37.1-py2.py3-none-any.whl",
sha256: "4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a",
destination: [file("${DEPS_DIR}/Debugger-rmi-trace/"), file("${DEPS_DIR}/PyGhidra/")]
],
[
name: "Pybag-2.2.12-py3-none-any.whl",
url: "https://files.pythonhosted.org/packages/ce/78/91db67e7fe1546dc8b02c38591b7732980373d2d252372f7358054031dd4/Pybag-2.2.12-py3-none-any.whl",
sha256: "eda5ee6c4e873902981b7f525b42a02428b87c7368df2c5bdfe1ded0e6884126",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "capstone-5.0.1-py3-none-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/d0/dd/b28df50316ca193dd1275a4c47115a720796d9e1501c1888c4bfa5dc2260/capstone-5.0.1-py3-none-win_amd64.whl",
sha256: "1bfa5c81e6880caf41a31946cd6d2d069c048bcc22edf121254b501a048de675",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "comtypes-1.4.1-py3-none-any.whl",
url: "https://files.pythonhosted.org/packages/50/8f/518a37381e55a8857a638afa86143efa5508434613541402d20611a1b322/comtypes-1.4.1-py3-none-any.whl",
sha256: "a208a0e3ca1c0a5362735da0ff661822801dce87312b894d7d752add010a21b0",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "pywin32-306-cp312-cp312-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl",
sha256: "37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e",
destination: file("${DEPS_DIR}/Debugger-agent-dbgeng/")
],
[
name: "packaging-23.2-py3-none-any.whl",
url: "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl",
sha256: "8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp313-cp313-macosx_10_13_universal2.whl",
url: "https://files.pythonhosted.org/packages/76/be/b37005bec457b94eaaf637a663073b7c5df70113fd4ae4865f6e386c612f/jpype1-1.5.2-cp313-cp313-macosx_10_13_universal2.whl",
sha256: "4acb098cb1698b14b6e5c79e275f4c70dcc01b0fb93425f206d0a5e380e43c66",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
url: "https://files.pythonhosted.org/packages/20/a3/00a265d424f7d47e0dc547df2320225ce0143fec671faf710def41404b8c/jpype1-1.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
sha256: "c08480c7d18125664a12bf0a244b96b49c05105306b65937dbefeb05ab4b2847",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
url: "https://files.pythonhosted.org/packages/6d/d0/191db2e9ab6ae7029368a488c9d88235966843b185aba7925e54aa0c0013/jpype1-1.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
sha256: "42fe8db66ad4e5c66f637f5c4de82fca880ba696104e1f4a7e575885923dead8",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp313-cp313-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/e3/b7/e1787633b41d609320b41d0dd87fe3118598210609e4e3f6cef93cfcef40/jpype1-1.5.2-cp313-cp313-win_amd64.whl",
sha256: "2b96365f1302df2fb3c6ad73117d6fe450a55b7550fd7fecadac3cec5bc7117c",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp312-cp312-macosx_10_9_universal2.whl",
url: "https://files.pythonhosted.org/packages/8d/e4/0c27352e8222dcc0e3ce44b298015072d2057d08dd353541c980a31d26c9/jpype1-1.5.2-cp312-cp312-macosx_10_9_universal2.whl",
sha256: "1e1db9ac909ad2ae0e40b04c2aa88cb14250d5245d69715561507681f2b08b2f",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
url: "https://files.pythonhosted.org/packages/fa/4c/e0200a6e3fed5cda79e926c2a8a610676f04948f89d7e38d93c7d4b21be9/jpype1-1.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
sha256: "994fb7b319b453f77ad4b6aff01e0dd4180ea74a6fe5a031e4e9db92dbe95376",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
url: "https://files.pythonhosted.org/packages/74/f3/1cd4332076ed0421e703412f47f15f43af170809435c57ba3162edc80d4b/jpype1-1.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
sha256: "b5b1fb2b430a50f081ea0ee24d19232ae0d03dbfe3dd076ec5f8ae42b30a656f",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp312-cp312-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/74/dd/7408d4beae755de6fcd07c76b2f0bacabc0461b43fba83811c1f7c22440e/jpype1-1.5.2-cp312-cp312-win_amd64.whl",
sha256: "c7b1c2d76d211cab60be16505d32a6b3c9fffc51ce79c68e81a3d48e5effff2d",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp311-cp311-macosx_10_9_universal2.whl",
url: "https://files.pythonhosted.org/packages/35/a0/638186a75026a02286041e4a0449b1dff799a3914dc1c0716ef9b9367b73/jpype1-1.5.2-cp311-cp311-macosx_10_9_universal2.whl",
sha256: "c9f6ab8dd284c16e2617a697d54c3d0304b08020a37386ed96103a129391a2d9",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
url: "https://files.pythonhosted.org/packages/0e/78/95db2eb3c8a7311ee08a2c237cea24828859db6a6cb5e901971d3f5e49da/jpype1-1.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
sha256: "a54a771ee56260f98e5b9a77455084e4a48061967de13dabf628bdba9c8122e0",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
url: "https://files.pythonhosted.org/packages/0b/7d/9fdbbc1a574be43f9820735ca8df0caf8b159856201d9b21fd73932342bc/jpype1-1.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
sha256: "b900e154826a076118d074166596f1d817e113e07084bf0c9c43d8064a86ab77",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp311-cp311-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/0e/b9/4dfb38a7f4efb21f71df7344944a8d9a23e30d0503574e455af6ce4f1a56/jpype1-1.5.2-cp311-cp311-win_amd64.whl",
sha256: "0a0d18d4384b3df2e55282545737dfcf18c604504f1382ad14f880bef960f265",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp310-cp310-macosx_10_9_universal2.whl",
url: "https://files.pythonhosted.org/packages/c7/f2/b2efcad1ea5a541f125218e4eb1529ebb8ca18941264c879f3e89a36dc35/jpype1-1.5.2-cp310-cp310-macosx_10_9_universal2.whl",
sha256: "7b2da98c142812ca40a18a735b33e47c6511b03debf1e979630f4cf473b68a87",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
url: "https://files.pythonhosted.org/packages/c0/c6/63538d160c17e837f62d29ba4163bc444cef08c29cd3f3b8090691c1869c/jpype1-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
sha256: "fcfc5c1d45d6b108800d172ea817bda585db7f1646d6a98d14da9aca66e0eb44",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
url: "https://files.pythonhosted.org/packages/97/0a/cbe03759331c640aa5862f974028122a862b08935a0b11b8fa6f6e46c26b/jpype1-1.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
sha256: "cdca93cc74f8db1f604d2ea6adb764dec4dec68528f1ee68308fa3d524095739",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp310-cp310-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/22/18/0a51845ca890ffdc72f4d71a0c2be334b887c5bb6812207efe5ad45afcb3/jpype1-1.5.2-cp310-cp310-win_amd64.whl",
sha256: "924b0a0cf93d3dddb3f79286fbe40f8c901c78ed61216edbe108666234df43e0",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl",
url: "https://files.pythonhosted.org/packages/05/71/590b2a91b43763aa27eac2c63803542a2878a4d8c600b81aa694d3fde919/jpype1-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl",
sha256: "8b75d33e93a3bc6543ddf97c24ee0adb5a86a69fb67f0e4f4fa1c8c3970bbf98",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
url: "https://files.pythonhosted.org/packages/77/6b/130fb6d0c43976b4e129c6bc19daf0e25c42fc38c5096ed92c4105bfd2c4/jpype1-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
sha256: "ea21bca4cece752cd3ee88fcd62ce8f444feac8dc7244475fdb9c0e8712e07ea",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
url: "https://files.pythonhosted.org/packages/77/91/f08a719461a390b48d9096b50f1f4a49ee281007ec192e51073090d3d8b7/jpype1-1.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
sha256: "54744265ef36665d110d139a4b81d10532694c6077b23ef60f3609feadc22d30",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2-cp39-cp39-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/e5/cf/344e1f81f1e8c651ec23dfa9fe4b91f6e1d699b36f610a547ba85ee7fb16/jpype1-1.5.2-cp39-cp39-win_amd64.whl",
sha256: "68e1d118200fc46f4ea4bf20900081587ec04de484037c997b0a3b7c5eb71fe3",
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "jpype1-1.5.2.tar.gz",
url: "https://files.pythonhosted.org/packages/bd/68/47fa634cbd0418cbca86355e9421425f5892ee994f7338106327e49f9117/jpype1-1.5.2.tar.gz",
sha256: "74a42eccf21d30394c1832aec3985a14965fa5320da087b65029d172c0cec43b",
destination: file("${DEPS_DIR}/PyGhidra/")
]
]
// Download dependencies (if necessary) and verify their hashes
mkdirs(DOWNLOADS_DIR)
deps.each {
File file = new File(DOWNLOADS_DIR, it.name)
if (OFFLINE || !it.sha256.equals(generateHash(file))) {
download(it.url, file)
if (!OFFLINE) {
assert(it.sha256.equals(generateHash(file)));
}
}
}
// Copies the downloaded dependencies to their required destination.
// Some downloads require pre-processing before their relevant pieces can be copied.
deps.each {
def copier = { File fp ->
if (!OFFLINE) {
println "Copying " + it.name + " to " + fp
}
mkdirs(fp)
copyFile(new File(DOWNLOADS_DIR, it.name), new File(fp, it.name));
}
if (it.destination instanceof File) {
copier(it.destination)
}
else if (it.destination instanceof List<File>) {
it.destination.each { fp ->
copier(fp)
}
}
else if (it.destination instanceof Closure) {
if (!OFFLINE) {
println "Processing " + it.name
}
it.destination()
}
else {
throw new GradleException("Unexpected destination type: " + it.destination)
}
}
//-------------------------------------Helper methods----------------------------------------------
/**
* Downloads a file from a URL. The download attempt will be tried NUM_RETRIES times before failing.
*
* Progress is shown on the command line in the form of the number of bytes downloaded and a
* percentage of the total.
*
* Note: We do not validate that the number of bytes downloaded matches the expected total here; any
* discrepencies will be caught when checking the SHA-256s later on.
*
* @param url the file to download
* @param file the local file to create for the download
*/
def download(url, file) {
if (OFFLINE) {
println "curl -L -o " + relative(file) + " '" + url + "'"
return
}
println "URL: " + url
def(InputStream istream, size) = establishConnection(url, NUM_RETRIES);
assert istream != null : " ***CONNECTION FAILURE***\n max attempts exceeded; exiting\n"
FileOutputStream ostream = new FileOutputStream(file);
def dataBuffer = new byte[1024];
int bytesRead;
int totalRead;
if (HIDE_DOWNLOAD_PROGRESS) {
print " Downloading..."
}
while ((bytesRead = istream.read(dataBuffer, 0, 1024)) != -1) {
ostream.write(dataBuffer, 0, bytesRead);
totalRead += bytesRead
if (!HIDE_DOWNLOAD_PROGRESS) {
print "\r"
print " Downloading: " + totalRead + " of " + size
if (!size.equals("???")) {
int pctComplete = (totalRead / size) * 100
print " (" + pctComplete + "%)"
}
print " " // overwrite gradle timer output
System.out.flush()
}
}
println()
istream.close();
ostream.close();
}
/**
* Attempts to establish a connection to the given URL
*
* @param url the URL to connect to
* @param retries the number of times to attempt to connect if there are failures
* @return the InputStream for the URL, and the size of the download in bytes as a string
*/
def establishConnection(url, retries) {
for (int i = 0; i < retries; i++) {
try {
if (i == 0) {
println " Connecting..."
}
else {
println " Connecting (" + (i+1) + "/" + retries + ")..."
}
URLConnection conn = new URL(url).openConnection();
conn.setRequestMethod("HEAD");
def size = conn.getContentLengthLong();
if (size == -1) {
size = "???"
}
return [new BufferedInputStream(new URL(url).openStream()), size];
}
catch (Exception e) {
println " Connection error! " + e
}
}
}
/**
* Unzips a file to a directory
*
* @param sourceDir the directory where the zip file resides
* @param targetDir the directory where the unzipped files should be placed
* @param zipFileName the name of the file to unpack
*/
def unzip(sourceDir, targetDir, zipFileName) {
def zipFile = new File(sourceDir, zipFileName)
if (OFFLINE) {
println "unzip " + relative(zipFile) + " -d " + relative(targetDir)
return
}
def zip = new ZipFile(zipFile)
zip.entries().findAll { !it.directory }.each { e ->
(e.name as File).with { f ->
if (f.parentFile != null) {
File destPath = new File(targetDir.path, f.parentFile.path)
mkdirs(destPath)
File targetFile = new File(destPath.path, f.name)
targetFile.withOutputStream { w ->
w << zip.getInputStream(e)
}
}
}
}
zip.close()
}
/**
* Creates the given directory, including any necessary but nonexistent parent directories
*
* @return true if and only if the directory was created, along with all necessary parent
* directories; false otherwise
*/
def mkdirs(dir) {
if (OFFLINE) {
if (!createdDirs.contains(dir)) {
println "mkdir -p " + relative(dir)
createdDirs << dir
}
return
}
return dir.mkdirs()
}
/**
* Copies a file to a new location
*
* @param sourceFile the file to copy
* @param targetFile the new file
*/
def copyFile(sourceFile, targetFile) {
if (OFFLINE) {
println "cp " + relative(sourceFile) + " " + relative(targetFile)
return
}
FileUtils.copyFile(sourceFile, targetFile)
}
/**
* Copies a filtered directory to a new location
*
* @param sourceDir the directory to copy
* @param targetDir the new directory
* @param filter the filter to apply; null to copy everything
*/
def copyDirectory(sourceDir, targetDir, filter) {
if (OFFLINE) {
println "cp -r " + relative(sourceDir) + " " + relative(targetDir)
return
}
FileUtils.copyDirectory(sourceDir, targetDir, filter)
}
/**
* Returns the path of the file relative to the repository
*
* @return The path of the file relative to the repository
*/
def relative(file) {
return "\"" + file.absolutePath.substring(REPO_DIR.absolutePath.length() + 1).replaceAll("\\\\", "/") + "\""
}
/**
* Generates the SHA-256 hash for the given file
*
* @param file the file to generate the SHA-256 hash for
* @return the generated SHA-256 hash, or null if the file does not exist
*/
def generateHash(file) {
if (!file.exists()) {
return null
}
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(Files.readAllBytes(Paths.get(file.path)));
byte[] digest = md.digest();
StringBuilder sb = new StringBuilder();
for (byte b : digest) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}