gradle cache目录(.gradle)剖析
https://zhuanlan.zhihu.com/p/26473930
gradle下载后会对文件路径进行修饰,本文给出反向解析,把文件路径修改为原始路径的办法。
之所以研究这个,本来的目的是为了让Gradle支持离线编译,但是由于Gradle目录组织的缺陷,如.gradle/caches/modules-2/metadata-2.23(metadata-xx跟使用的gradle版本有关)目录下module-artifacts.bin等bin文件中存的是本机的绝对路径,导致就算将.gradle拷贝给另一台机器,还是需要联网验证。
将gradle的jcenter重定向的方法见我的另一篇文章:[android]gradle下载加速 - 知乎专栏,例如阿里云的jcenter是Index of /repositories/jcenter
我在内网中搭建了jcenter仓库。然而我不想搭建一个大而全的jcenter的仓库,搭建大而全的仓库可以使用nexus来搭建,阿里云也是那么搭的,由于公司的网络需要上网认证,时不时会断一下,所以我的做法是通过利用.gradle目录来创建jcenter仓库。
下面先介绍.gradle目录的组织。
1 .gradle顶级目录
目录| 功能
caches | gradle缓存目录
daemon | daemon日志目录
native | gradle平台相关目录
wrapper | gradle-wrapper下载目录
2 caches目录
目录 | 功能
2.14.1 | gradle程序的脚本(gradle程序版本)
3.2.1 | gradle程序的脚本(gradle程序版本)
jars-1 | ?
jars-2 | ?
modules-2 | 下载缓存目录
2.1 caches/modules-2目录
目录 | 功能
files-2.1 | gradle下载的jar/aar目录
metadata-2.16 | gradle-2.14.1的描述文件?
metadata-2.23 | gradle-3.2.1的描述文件?
2.1.1 files-2.1的目录组织(jar/aar都下载到这里)
${org}/${package}/${version}/${shanum1}/${package-version}.pom
${org}/${package}/${version}/${shanum2}/${package-version}.jar
例如:
#jcenter上jar的路径
https://jcenter.bintray.com/com/android/tools/lint/lint-api/25.1.3/lint-api-25.1.3.jar
#对应的缓存目录为
.gradle/caches/modules-2/files-2.1/com.android.tools.lint/lint-api/25.1.3/${shasum1}/lint-api-25.1.3.jar
#看下这个目录下有什么?
~ find .gradle/caches/modules-2/files-2.1/com.android.tools.lint/lint-api/25.1.3/ -type f
#除了jar包还有pom,用于描述jar。
.gradle/caches/modules-2/files-2.1/com.android.tools.lint/lint-api/25.1.3/14c6a94811fb8114a61b8f3ab29214f9466b5c59/lint-api-25.1.3.jar
.gradle/caches/modules-2/files-2.1/com.android.tools.lint/lint-api/25.1.3/c4844e26d84dd1f450f90d89d7e2d2d09f52760/lint-api-25.1.3.pom
#看下jar的shasum
~ shasum .gradle/caches/modules-2/files-2.1/com.android.tools.lint/lint-api/25.1.3/14c6a94811fb8114a61b8f3ab29214f9466b5c59/lint-api-25.1.3.jar
14c6a94811fb8114a61b8f3ab29214f9466b5c59 .gradle/caches/modules-2/files-2.1/com.android.tools.lint/lint-api/25.1.3/14c6a94811fb8114a61b8f3ab29214f9466b5c59/lint-api-25.1.3.jar
#即目录名。
注意:创建jcenter时,对于jar包,可以没有pom,但是如果使用aar,则必须有pom,所以最好是每个版本都有个pom。因为pom中也描述了依赖关系。
3 daemon目录(无需离线)
用于存放gradle daemon的运行日志。按gradle程序版本存放。
目录 | 功能
2.14.1 | gradle-2.14.1运行的日志
3.2.1 | gradle-3.2.1运行的日志
4 native目录(无需离线)
用于存放平台相关(Win/Linux/Mac)的库。
目录 | 功能
19 | gradle-2.14.1对应的lib目录,按平台存放,如osx-amd64
21 | gradle-3.2.1对应的lib目录,按平台存放,如osx-amd64
jansi | ?
5 wrapper目录
用于存放gradle-wrapper下载gradle的zip包和解压后的文件夹。
wrapper的目录规则是
wrapper/dists/gradle-2.14.1-all/${base36}/gradle-2.14.1-all.zip
wrapper/dists/gradle-2.14.1-all/${base36}/gradle-2.14.1-all.zip.lck
wrapper/dists/gradle-2.14.1-all/${base36}/gradle-2.14.1-all.zip.ok
其中base36的规则为:
- 从gradle/wrapper/gradle-wrapper.properties中得到distributionUrl,即https://services.gradle.org/distributions/gradle-2.14.1-all.zip,注意文件中的\不算。
- 对distributionUrl计算md5。例如printf “https://services.gradle.org/distributions/gradle-2.14.1-all.zip” | md5
得到8c9a3200746e2de49722587c1108fe87。 - 利用0x8c9a3200746e2de49722587c1108fe87构造一个uint 128位整数。
- 将整数利用base36得到base36的值(取小写)。
从gradle-wrapper的jar包中提取的Java代码如下:
import java.math.BigInteger;
import java.security.MessageDigest;
public class Hash {
public static void main(String[] args) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
byte[] bytes = args[0].getBytes();
messageDigest.update(bytes);
String str = new BigInteger(1, messageDigest.digest()).toString(36);
System.out.println(str);
} catch (Exception e) {
throw new RuntimeException("Could not hash input string.", e);
}
}
}
c++跟java代码见http://github.com/xiaoyur347/gradlew/helper。
6. 使用.gradle/caches/modules-2创建jcenter的方法
以下是mirror.sh,我把它放在.gradle目录下。运行脚本会在.gradle目录下生成jcenter目录。把它移走或直接把jcenter目录加入http服务器即可。
目前我的做法是在本地使用gradle编译一次,然后把gradle下载下来的jar/aar/pom全部提交到版本管理,然后由持续集成去拉版本库上的.gradle目录,然后生成jcenter提供给内网编译服务器。
#!/bin/bash
#use .gradle/caches/modules-2/files-2.1/ to create jcenter
SHPATH=$(cd "$(dirname "$0")"; pwd)
DIR="${SHPATH}/caches/modules-2/files-2.1/"
DIR_LENGTH=${#DIR}
if [ `uname` = "Darwin" ]; then
#mac will add "/"
DIR_LENGTH=$((DIR_LENGTH+1))
fi
rm -rf ${SHPATH}/jcenter/*
find ${DIR} -type f | grep -Ev "DS_Store" | while read line
do
SRC=${line}
URL=${line:${DIR_LENGTH}}
ORG=${URL%%/*}
URL=${URL#*/}
MODULE=${URL%%/*}
URL=${URL#*/}
REVISION=${URL%%/*}
URL=${URL#*/}
SHA1=${URL%%/*}
URL=${URL#*/}
FILE=${URL}
#echo "ORG=$ORG, MODULE=$MODULE, REVISION=$REVISION, SHA1=$SHA1, FILE=$FILE"
DST=${SHPATH}/jcenter/${ORG//.//}/${MODULE}/${REVISION}/${FILE}
echo "$DST"
mkdir -p `dirname ${DST}`
if [ ! -f ${DST} ]; then
cp -a ${SRC} ${DST}
fi
done
另外,上面提到aar有可能会因为缺失pom导致无法使用,我还写了一个脚本,也是放在.gradle目录下,用于修复aar问题。本地运行时,可以只运行这个脚本,因为它会顺路执行上面的脚本。
以下是fix_aar_cache.sh的内容:
#!/bin/bash
SHPATH=$(cd "$(dirname "$0")"; pwd)
SRC_DIR=${SHPATH}/jcenter
CACHE_DIR="${SHPATH}/caches/modules-2/files-2.1/"
${SHPATH}/mirror.sh > /dev/null
DIR_LENGTH=${#SRC_DIR}
if [ `uname` = "Darwin" ]; then
#mac will add "/"
DIR_LENGTH=$((DIR_LENGTH+1))
fi
find ${SRC_DIR} -name "*.aar" | while read line
do
SRC=${line}
LOCAL_POM=${SRC/.aar/.pom}
if [ -f ${LOCAL_POM} ]; then
continue
fi
echo "$LOCAL_POM not found"
URL=${line:${DIR_LENGTH}}
URL=${URL/.aar/.pom}
REMOTE_POM=http://maven.aliyun.com/nexus/content/repositories/jcenter/${URL}
REMOTE_POM_SHA1=${REMOTE_POM}.sha1
SHA1=`wget -q -O- ${REMOTE_POM_SHA1}`
SHA1=${SHA1:2} #remove additional \r\n
echo $SHA1
#reverse to get it
FILE=${URL##*/}
URL=${URL%/*}
REVISION=${URL##*/}
URL=${URL%/*}
MODULE=${URL##*/}
URL=${URL%/*}
ORG=${URL}
echo "ORG=$ORG, MODULE=$MODULE, REVISION=$REVISION, FILE=$FILE"
#org /->.
DST=${CACHE_DIR}/${ORG//\//\.}/${MODULE}/${REVISION}/${SHA1}/${FILE}
echo "$DST"
mkdir -p `dirname ${DST}`
if [ ! -f ${DST} ]; then
wget -O ${DST} ${REMOTE_POM}
fi
done
gradle cache目录(.gradle)剖析的更多相关文章
- Android Studio Gradle 缓存目录设置
======================================================== 笔者:qiujuer 博客:blog.csdn.net/qiujuer 站点:www. ...
- gradle用户目录本地库移动设置
gradle被越来越多的程序开发人员使用来构件项目代码,使用gradle依赖的第三方jar包有时候非常占空间,默认这样的用户本地库目录(缓存目录)在系统盘上,我们可以修改用户目录到其它盘上 工具/原料 ...
- Intellij IDEA gradle项目目录介绍
Gradle简介 Java的构建,经历了从Ant-->Maven->Gradle的过程,每一次的进步,都是为了解决之前的工具带来的问题: Ant:Ant的功能虽然强大,但过于灵活,规范性不 ...
- Gradle学习目录总结
如果是你想干的事情,在别人看起来可能是很难的一件事,不过你自己很喜欢,你不会觉得很苦.我开始创业那会是28岁.对我来讲,我创业的目的不是为了自己当老板,我希望有一个平台有一个环境,我可以控制一些资源, ...
- Gradle之Android Gradle Plugin 主要 Task 分析(三)
[Android 修炼手册]Gradle 篇 -- Android Gradle Plugin 主要 Task 分析 预备知识 理解 gradle 的基本开发 了解 gradle task 和 plu ...
- Android(java)学习笔记127:Android Studio新建工程中的build.gradle、settings.gradle
随着信息化的快速发展,IT项目变得越来越复杂,通常都是由多个子系统共同协作完成.对于这种多系统.多项目的情况,很多构建工具都已经提供了不错的支持,像maven.ant.Gradle除了借鉴了ant或者 ...
- Chapter 4. Using the Gradle Command-Line 使用gradle命令行
This chapter introduces the basics of the Gradle command-line. You run a build using the gradle comm ...
- Gradle 同步 已经开始 Gradle sync started
Gradle 同步 已经开始 Gradle sync started 作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com E-mail: 31313 ...
- [Gradle] 如何强制 Gradle 重新下载项目的依赖库
强制刷新 Gradle 依赖库缓存 $ gradle build --refresh-dependencies The --refresh-dependencies option tells Grad ...
随机推荐
- open与fopen的用法
1. fopen 打开普通文件 带缓冲区 缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符.字符串.格式化数据,也可以读写二进制数据. 函数原 ...
- wcf文件上传时碰到的配置问题
1.远程服务器返回了意外相应:(413) Request Entity Too Large 修改客户端配置maxReceivedMessageSize="2147483647" & ...
- Partial关键字
Partial关键词定义的类可以在多个地方被定义,最后编译的时候会被当作一个类来处理. 首先看一段在C#中经常出现的代码,界面和后台分离,但是类名相同. public partial class Fo ...
- CENTOS7 使用 Nginx + Uwsgi 部署 Django 项目
写在前面的话 最近总是见到有新学 Django 的朋友在部署自己的项目到 Linux 上面的时候运行不起来,所以就动手写了这篇博客. 对于不会搭建 Python 3 环境的朋友可以参考前面的博客[CE ...
- 《Java多线程编程实战指南+设计模式篇》笔记
线程的监视:工具:jvisualvm.exe 命令:jstack PID 原子性: volatile关键字: 显示锁:人为实现的程序员可控制的锁,包括synchronized和Lock下的实现类: 线 ...
- NSProcessInfo系统进程信息
前言 NSProcessInfo 类中包含一些方法,允许你设置或检索正在运行的应用程序(即进程)的各种类型的信息. 1.获取系统进程信息 // 创建系统进程信息对象 NSProcessInfo *pr ...
- 看了这篇Dubbo RPC面试题,让天下没有难面的面试题!
前言: RPC非常重要,很多人面试的时候都挂在了这个地方!你要是还不懂RPC是什么?他的基本原理是什么?你一定要把下边的内容记起来!好好研究一下!特别是文中给出的一张关于RPC的基本流程图,重点中 ...
- 50个php程序性能优化的方法,赶紧收藏吧!
1. 用单引号代替双引号来包含字符串,这样做会更快一些.因为 PHP 会在双引号包围的 字符串中搜寻变量,单引号则不会,注意:只有 echo 能这么做,它是一种可以把多个字符 串当作参数的“函数”(译 ...
- python Exception
1.except:用来捕捉异常,如果没有捕捉到,则向上层exception传递 2.finally:用来保证其代码一定会执行,可以做收尾工作,比如关闭文件等等. 3.在with as 中, 4.try ...
- 一、pytest的介绍和安装
需要针对一个项目系统开发一套UI自动化测试脚本,自己结合着学习,采用了pytest去实现,这里留下记录. 什么是pytest pytest 是一个非常成熟的全功能的Python测试框架 可以胜任uni ...