• 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的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代码见

    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 
    
    	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
  • 相关阅读:
    python学习笔记:遍历目录
    c++笔记:友元函数
    VMware Workstation 9: This virtual machine's policies are too old to be run by this version of VMware
    inet_ntoa内存问题
    python学习笔记:sqlite3查询
    python学习笔记:利用asyncore的端口映射(端口转发)
    编写谷歌浏览器的油猴脚本
    window编译7z
    通过配置nginx的header路由到不同环境的服务器
    用U盘给物理机安装ubuntu20.04
  • 原文地址:https://www.cnblogs.com/shihuvini/p/10077425.html
Copyright © 2020-2023  润新知