遗失的源代码之回归之路的探索与实践

背景

最近比较突然被安排接手一个项目,该项目的情况如下

  • 原生和RN结合的混合开发模式
  • 组件化开发,有很多基础组件以及业务组件

但是在梳理项目依赖时发现了个别组件源码不全的情况,于是写了个cli用于对比两个版本产物文件,生成差异结果以便于快速进行源码找回恢复。
结果如下:
找回前的对比:
在这里插入图片描述

找回后对比:

在这里插入图片描述


遗失的源代码

在梳理项目时,我发现几个比较核心的组件依赖的版本跟git源码仓库的tag和发布版本不一致。

我尼玛顿时惊出一身冷汗,怕不是有些代码没提交吧!

经过核实,的确是部分代码没提交,判断依据如下:

  • 以核心组件A举例说明,它在壳子依赖的版本是2.0.0,但是源码仓库里发布配置的版本是1.0.0,并且找不到2.0.0版本的tag。
  • 源码仓库最新分支的最后一次提交时间比在maven私有仓库中2.0.0版本产物上传的时间早
  • 壳子对该组件的依赖时间从1.0.0变更为2.0.0的时间跟2.0.0版本产物上传的时间一致

由此可以确认,1.0.0到2.0.0之间的代码变更是没有提交到git仓库的,但是产物是打包并上传到私有仓库里了,所以壳子可以正常依赖使用。

找出问题

出现这种问题的原因是我们的组件打包上传流程并没有规范化,而是大家约定了一个打包上传的规范如下:

  1. 先提交代码,并打对应版本tag
  2. 然后再执行gradle打包上传脚本将对应版本的aar或者jar上传到maven私有仓库

但是这种靠人为执行约定流程是不可控的,有时候开发图省事直接自己在项目中执行一个gradle打包上传脚本把产物上传到maven私有仓库,然后壳子工程就可以依赖使用了,但是本地代码忘记提交到git仓库,也不会去打tag,这样就导致了可能出现产物版本是最新的,但是仓库源码并非最新的情况。

解决问题
出现这个问题的根本原因在于没有一个规范的管理流程,解决这个问题也比较简单,就是把开发直接打包上传到maven的权限收回,把打包操作后置例如放到CI上执行。
大致流程如下:

  1. 提供一个入口例如网页,网页上把git仓库管理起来
  2. 需要打包就在网页上选择对应的git仓库,网页把打包相关的配置展示出来,点击确定按钮触发CI打包流程
  3. CI去对应的git仓库执行内部对应的打包上传脚本即可

由于CI是直接去git仓库拉代码打包的,这样就避免出现了代码没提交,但是产物能出来的问题了。
当然,实现这个打包管理的流程设计到前后端以及CI,整体的细节和工作量还是不少的,上面只是一个大致流程。

实际上如何管理打包流程都是后话了,当务之急是要把新版本的代码找回来。
在梳理的时候其实发现了一个更严重的问题是,当时的项目RN升级一个大版本,做法是基于RN的源码做了些修改然后重新打包成aar给壳子工程依赖的,但是,那个基于RN源码定制的git仓库都找不到了,也就是我要先基于RN的源码编译出产物,然后还要找回已有aar和RN源码编译出来的aar之间的代码变更。本来我对RN就不熟悉,又出了这一档子事情,这不是给我加难度吗…
在这里插入图片描述


回归之路的探索

上面也说到了,当务之急是先把源码给恢复好,因为后续还需要基于恢复后的代码继续开发迭代,经过沟通过后得知是不可能再找到之前的开发看看能不能把没提交的代码给提交一下了。

那就只剩下一条路,自己尝试着恢复,那怎么恢复呢?
先来梳理一下现有的东西。

  • git仓库里有旧版本的源码,RN的话github上找对应版本的源码即可,
  • 有新版本的aar文件

思路一

很自然的一个思路就是Android Studio不是能直接看到依赖产物的的代码吗?
例如在这里插入图片描述
那我直接找到对应的产物,跟源码文件一个一个进行内容对比不就可以了。
当然这样理论上是可以实现的,但实际落地下来很难执行,原因如下:

  • 在打包成产物后的源码进行处理过后的,一些注释啊,空格啊,变量名啊,代码的顺序啊都会有变更,AS上显示的产物里的代码是对已经处理过的源码编译后的class文件进行反编译显示,那这样一来,跟原本的源代码就会产生很大的差异。

以RN的源码举例说明,下面是在AS上看的RN源码中的一个类

在这里插入图片描述

再来看下实际的源码
在这里插入图片描述

可以明显的看出从代码行数以及变量名都有变化,这还是一个非常简单的类,这种我们可以肉眼对比出来,RN源码中负责的类有非常多,这种我们如果一个一个对比肉眼去看,那简直是个灾难。

到这里实际上肉眼比较的方案其实已经执行不下去了,原因如下:

  1. 对于源码数量非常多的组件,工作量巨大,因为我们要对比每一个文件还有资源文件,确保找出增,删,改的文件
  2. 人工去对比最终的结果质量无法保证,基本可以遇见的是花了一上午对比了几个文件后就开始心情烦躁,情绪波动,最后直接开摆,扫一眼没啥问题就过。

在这里插入图片描述
3. 心智负担巨大,这种明显是属于吃力也不讨好的方案,最后人家问你确定恢复的没有问题吗?你真的敢说没问题吗?

思路二

基于思路一我们来看一下有什么问题

  • 直接看产物反编译后的代码跟旧版本源码比较差异大,难以确定是否变更
  • 对于代码量多的组件,工作量大,人工对比效率太低
  • 靠人工判断无法保证最终结果的正确性
代码差异大的问题

对于查看反编译后的产物跟源码比较差异大的问题,想办法让他们俩尽量在状态比较一致的情况下再次对比。
我们可以把源码也打包编译成产物,然后对比两个版本产物反编译后的代码内容确定是否有变更。实际操作下来这种方式确实能够极大的减少代码差异大的情况

效率低的问题

上面也说到了,人工对比的心智负担比较大,例如RN源码有700多个类文件,一个一个对比下来先不说时间问题,准确度也没办法保证,毕竟,我们不能仅仅靠代码行数是否一致就去判断代码有没有变更。

准确度的问题

可以通过程序计算对比文件的md5值,给出最终的结果输出,保证最终还原的正确性

解决方案

可以做一个工具,把新老版本的产物丢进去,程序帮我们进行解压,遍历,反编译等操作,然后对反编译后的java文件进行md5值计算,最后输出结果,把md5值不同的文件输出出来,这样依赖,既可以保证每个文件都能对比到,还能确保最终的结果是稳定可靠的。

大致流程如下

  1. 将已有源码编译成产物aar
  2. 设计一个cli工具,用于处理两个版本的产物
  3. 对产物进行解压,先处理资源文件,计算文件的md5值
  4. 针对代码文件进行反编译,随后遍历反编译后的java文件,计算md5值
  5. 新老版本结果进行对比,找出增,删,改的文件
  6. 输出结果

回归之路的实践

确定好方案之后,就可以动手开发了,这里我选择是做一个cli工具。

初步实现

CLI工具可下载直接使用:下载地址 component-diff-1.0.0.jar
使用方式如下:

java -jar jar包路径 true --old 旧版本产物 --new新版本产物 --output 结果输出目录

参数说明

  • jar包路径:就是你下载的jar文件在你的电脑的绝对路径
  • true表示打印执行日志
  • --old后面跟你的旧版本的产物文件路径
  • --new 后面跟你的新版本的产物文件路径
  • --output 后面跟输出结果目录

示例:

java -jar /Users/yuzhiqiang/Documents/组件对比/component-diff-1.0.0.jar true --old //Users/yuzhiqiang/Documents/组件对比/rn_source/old/react-native-0.68.5.aar --new /Users/yuzhiqiang/Documents/组件对比/rn_source/new/react-native-0.68.513.aar --output /Users/yuzhiqiang/Documents/组件对比/r

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/450945.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2、安全开发-Python-Socket编程端口探针域名爆破反弹Shell编码免杀

用途:个人学习笔记,欢迎指正! 目录 主要内容: 一、端口扫描(未开防火墙情况) 1、Python关键代码: 2、完整代码:多线程配合Queue进行全端口扫描 二、子域名扫描 三、客户端,服务端Socket编程通信cmd命…

SpringCloud-微服务项目架构

在当今软件开发领域,微服务架构正成为构建灵活、可伸缩、独立部署的应用的首选,微服务架构作为一种灵活而强大的设计模式,通过将系统拆分为独立的、自治的服务,使得应用更容易维护、扩展和升级。本文将探讨微服务项目架构的关键特…

数据在内存中的存储(上)

1. 整数在内存中的存储 整数的2进制表示方法有三种:即原码、反码和补码 三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位最 高位的一位是被当做符号位,剩余的都是数值位。 正…

流畅的Python(七)-函数装饰器和闭包

一、核心要义 主要解释函数装饰器的工作原理,包括最简单的注册装饰器和较复杂的参数化装饰器。同时,因为装饰器的实现依赖于闭包,因此会首先介绍闭包存在的原因和工作原理。 二、代码示例 1、变量作用域规则 #!/usr/bin/env python # -*-…

uniapp 高德地图显示

1. uniapp 高德地图显示 使用前需到**高德开放平台(https://lbs.amap.com/)**创建应用并申请Key   登录 高德开放平台,进入“控制台”,如果没有注册账号请先根据页面提示注册账号   打开 “应用管理” -> “我的应用”页面…

Python—数据可视化Seaborn大全:参数详解与实战案例全解析【第52篇—python:Seaborn大全】

文章目录 Seaborn库常用绘图详解与实战引言安装与导入一、散点图参数说明实战案例 二、直方图参数说明实战案例 三、线性关系图参数说明实战案例 四、热力图参数说明实战案例 五、分布图参数说明实战案例 六、箱线图参数说明实战案例 七、联合分布图参数说明实战案例 八、小提琴…

AJAX-常用请求方法和数据提交

常用请求方法 请求方法:对服务器资源,要执行的操作 axios请求配置 url:请求的URL网址 method:请求的方法,如果是GET可以省略;不用区分大小写 data:提交数据 axios({url:目标资源地址,method…

ES6-数组的解构赋值

一、数组的解构赋值的规律 - 只要等号两边的模式相同,左边的变量就会被赋予对应的值二、数组的解构赋值的例子讲解 1)简单的示例(完整的解构赋值) 示例 //基本的模式匹配 // a,b,c依次和1,2&#xff0c…

freeswitch对接FunASR实时语音听写

1、镜像启动 通过下述命令拉取并启动FunASR软件包的docker镜像: sudo docker pull \registry.cn-hangzhou.aliyuncs.com/funasr_repo/funasr:funasr-runtime-sdk-online-cpu-0.1.7 mkdir -p ./funasr-runtime-resources/models sudo docker run -p 10096:10095 -i…

ctfshow web-77

开启环境: 先直接用伪协议获取 flag 位置。 c?><?php $anew DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString(). );} exit(0); ?> 发现 flag36x.txt 文件。同时根目录下还有 readflag&#xff0c;估计需要调用 readflag 获…

java hutool工具类实现将数据下载到excel

通过hutool工具类&#xff0c;对于excel的操作变得非常简单&#xff0c;上篇介绍的是excel的上传&#xff0c;对excel的操作&#xff0c;核心代码只有一行。本篇的excel的下载&#xff0c;核心数据也不超过两行&#xff0c;简洁方便&#xff0c;特别适合当下的低代码操作。 下载…

Kettle 解决数据同步缓慢及性能效率问题 (数据同步利用时间戳解耦,性能通过配置优化提升90%)

一. 介绍 在数据同步过程中&#xff0c;缓慢的同步速度和低效率的性能往往是令人头痛的问题。本文将介绍如何通过Kettle解决数据同步缓慢及性能效率问题&#xff0c;其中主要涉及数据同步利用时间戳解耦和通过配置优化提升性能高达90%的方法 。 在先前的博客文章中&#xff0c…