使用MD5对项目文件进行加密

一个简单的脚本,没有复杂的操作,主要目的是对主线代码和上线的产品代码进行对比,验证两份代码的一致性

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
@author: dgz
@contact: duanguozeng@linezonedata.com
@software: pycharm
@file: md5_encryption.py
@time: 2020/08/11
@desc: 该脚本主要目的是: 生成版本代码的MD5码, 用于对比项目代码和产品代码是否相同
"""

import os
import sys
import chardet
import hashlib

BASE_PATH = os.path.abspath('.')


class Md5Encryption(object):

    def __init__(self, base_path):
        # 项目主路径
        self.base_path = base_path

        # 收集文件列表
        self.files_list = []

        # 收集MD5码文件
        self.md5_file = self.base_path + '/md5.txt'

        # 换行分隔符的模式
        self.tp = ''

        # 自定义数据
        self.custom = None

        # 默认忽略的文件和文件夹 这里的文件或文件夹,需要填入相对路径
        self.ignore = ['.git', '.idea', 'md5_encryption.py', '/src/extend_dev']

    def custom_files_or_dirs(self):
        """
        自定义生成MD5码的文件
        -D: 不生成MD5码的文件夹
        -d: 仅生成指定文件夹下文件的MD5码
        -F: 不生MD5码的文件
        -f: 仅对指定文件生成MD5码
        -a: 对所有文件进行处理
        -h: 帮助
        :return: custom_list
        """
        print('开始按照{0}模式收集文件'.format(sys.argv[1]))

        if '-D' == sys.argv[1]:
            custom_list = sys.argv[2:]
            files_list = self.ignore_dirs(self.base_path, custom_list)
        elif '-d' == sys.argv[1]:
            custom_list = sys.argv[2:]
            files_list = self.dispose_dirs(self.base_path, custom_list)
        elif '-F' == sys.argv[1]:
            custom_list = sys.argv[2:]
            files_list = self.dispose_files(self.base_path, custom_list)
            print(len(files_list))
        elif '-f' == sys.argv[1]:
            custom_list = sys.argv[2:]
            files_list = self.dispose_files(self.base_path, custom_list)
            print(len(files_list))
        elif '-a' == sys.argv[1]:
            files_list = self.get_all_files(self.base_path)
        elif '-h' == sys.argv[1]:
            print("""
                    1. 脚本执行命令: python md5_encryption.py [自定义数据参数类型] [数据]
                    2. 自定义数据参数类型有: '-D', '-d', '-F'. '-f'
                    3. 数据之间用空格隔开
                    4. -D: 不生成MD5码的文件夹
                       -d: 仅生成指定文件夹下文件的MD5码
                       -F: 不生MD5码的文件
                       -f: 仅对指定文件生成MD5码
                       -a: 对所有文件进行处理
                       -h: 帮助
                   """)
            sys.exit(0)
        else:
            raise Exception('自定义数据参数传入异常, 仅支持 "-D", "-d", "-F", "-f" 参数选择')

        if not files_list:
            raise TypeError('文件收集异常,当前文件收集模式是{0}'.format(sys.argv[1]))
        else:
            lz_logger.info('文件收集成功')
        return files_list

    def ignore_dirs(self, base_path, custom_list=None):
        """
        忽略不生成MD5的文件夹
        :param base_path: 路径
        :param custom_list: 待处理的文件列表
        :return: 收集的文件列表
        """
        base_dir_list = self.ignore_default_dir(base_path)

        for item in base_dir_list:
            src = os.path.join(base_path, item)
            if os.path.exists(src):
                if item in custom_list:
                    continue
                else:
                    if os.path.isdir(src):
                        self.ignore_dirs(src, custom_list)
                    else:
                        self.add_files(src)
            else:
                raise IOError('{}: 当前文件或文件夹不存在!'.format(src))

        return self.files_list

    def dispose_dirs(self, base_path, custom_list=None):
        """
        处理需要生成MD5的文件夹
        :param base_path: 路径
        :param custom_list: 待处理的文件列表
        :return: self.files_list
        """
        if base_path != self.base_path:
            custom_list = os.listdir(base_path)
        custom_list.sort()

        for item in custom_list:
            src = os.path.join(base_path, item)
            if os.path.exists(src):
                if os.path.isdir(src):
                    self.dispose_dirs(src, custom_list)
                else:
                    self.add_files(src)
            else:
                raise IOError('{}: 当前文件或文件夹不存在!'.format(src))
        return self.files_list

    def dispose_files(self, base_path, custom_list=None):
        """
        处理文件
        :param base_path: 文件路径
        :param custom_list: 待处理的文件列表
        :return: self.files_list
        """
        base_dir_list = self.ignore_default_dir(base_path)

        for item in base_dir_list:
            src = os.path.join(base_path, item)
            if os.path.exists(src):
                if os.path.isdir(src):
                    self.dispose_files(src, custom_list)
                else:
                    if sys.argv[1] == '-F':
                        if item in custom_list:
                            continue
                        else:
                            self.add_files(src)
                    elif sys.argv[1] == "-f":
                        if item in custom_list:
                            self.add_files(src)
                        else:
                            continue

            else:
                raise IOError('{}: 当前文件或文件夹不存在!'.format(src))
        return self.files_list

    def ignore_default_dir(self, base_path):
        """
        处理默认需要忽略掉的文件或文件夹
        :param base_path: 路径
        :return: base_dir_list
        """
        base_dir_list = os.listdir(base_path)
        base_dir_abs_path_list = [os.path.join(base_path, path) for path in base_dir_list]
        for data in self.ignore:
            data_path = self.base_path + data
            if data_path in base_dir_abs_path_list:
                base_dir_list.remove(os.path.basename(data_path))
        base_dir_list.sort()
        return base_dir_list

    def get_all_files(self, base_path):
        """
        获取所有.py或.sh结尾的文件列表
        :param base_path: 文件路径
        :return: self.files_list
        """
        base_dir_list = self.ignore_default_dir(base_path)

        for item in base_dir_list:

            src = os.path.join(base_path, item)
            if os.path.exists(src):
                if os.path.isdir(src):
                    self.get_all_files(src)
                else:
                    self.add_files(src)
            else:
                raise IOError('{}: 当前文件或文件夹不存在!'.format(src))
        return self.files_list

    def add_files(self, path):
        if os.path.exists(path):
            if os.path.isfile(path):
                if (os.path.basename(path).endswith('.py') or os.path.basename(path).endswith('.sh')) \
                        and os.path.getsize(path) != 0:
                    self.files_list.append(path)
        else:
            raise IOError('{}: 当前文件不存在!'.format(path))
        return True

    def format_conversion(self, files_list):
        """
        用于同一文件的格式, 不同操作系统的换行分割符不同,会导致同一代码的MD5码不同
        所以统一项目的换行分割符是 LF
        :param files_list:
        :return:
        """
        if not files_list:
            raise TypeError('文件列表为空, 收集文件时异常')
        else:
            for path in files_list:
                file_name = os.path.basename(path)
                print('开始格式化: {0}'.format(file_name))
                read_data = self.read_file(path)
                encoding = chardet.detect(read_data)['encoding']
                data_str = read_data.decode(encoding)
                print('{0}: 文件正常读入'.format(file_name))

                if '\r\n' in data_str:
                    self.tp = "CRLF"
                    data_str = data_str.replace('\r\n', '\n')
                    print('将Windows系统的换行分割符CRLF转为Unix and OS X 的 LF')
                elif '\r' in data_str:
                    self.tp = "CR"
                    data_str = data_str.replace('\r', '\n')
                    print('将Classic Mac系统的换行分割符CRLF转为Unix and OS X 的 LF')

                if encoding not in ['utf-8', 'ascii'] or self.tp == 'CR' or self.tp == 'CRLF':
                    try:
                        with open(path, 'w', newline='\n', encoding='utf-8') as f:
                            f.write(data_str)
                    except IOError:
                        print('格式化文件{0}写入异常'.format(file_name))
                        print('格式化文件{0}写入异常'.format(file_name))
                print('格式化: {0} 成功'.format(file_name))
        print('文件格式统一化完成')
        return True

    def generate_hash(self, files_list):
        """
        用于生成每一个文件对应的MD5码
        :param files_list:
        :return:
        """
        if files_list:
            for file_path in files_list:
                file = os.path.basename(file_path)
                data = self.read_file(file_path)
                md5 = hashlib.md5(data).hexdigest()  # 生成MD5
                lz_logger.info('{0} 的MD5码: {1}'.format(file, md5))
                md5_data = file + ": " + md5
                md5_data = md5_data.encode("utf-8")
                self.write_md5_code_to_file(self.md5_file, md5_data)
            lz_logger.info('成功生成所有文件的MD5码')
        else:
            raise TypeError('files_list is empty! 文件收集异常')
        return True

    def version_md5(self):
        """
        生成版本对应的MD5码
        :return:
        """
        data = self.read_file(self.md5_file)
        md5 = hashlib.md5(data).hexdigest()
        md5_code = 'Version_md5_code:' + md5
        print('Version_md5_code: {0} '.format(md5))
        md5_code = md5_code.encode("utf-8")
        self.write_md5_code_to_file(self.md5_file, md5_code)
        print('当前版本MD5码成功生成')
        return True

    def read_file(self, file_path):
        """
        读取文件内容
        :param file_path:
        :return:
        """
        if not os.path.exists(file_path):
            raise IOError("读取文件失败! 文件不存在")
        else:
            try:
                with open(file_path, 'rb') as f:
                    data = f.read()
                    return data
            except IOError:
                print('文件读取异常')

    def write_md5_code_to_file(self, file_path=None, data=None):
        """
        写入文件内容
        :param file_path:
        :param data:
        :return:
        """
        try:
            with open(file_path, 'ab+') as f:
                write_data = data + '\n'.encode()
                f.write(write_data)
        except IOError:
            print('文件写入异常')

    def check_file(self):

        if os.path.exists(self.md5_file):
            print('收集MD5码文件已存在')
            os.remove(self.md5_file)
            print('删除MD5码收集文件')
        else:
            print('收集MD5码文件不存在')

        return True

    def run(self):
        files_list = self.custom_files_or_dirs()

        print('检查收集MD5码文件是否存在')
        self.check_file()

        print('开始统一文件格式')
        self.format_conversion(files_list)

        print('开始对每个文件生成对应MD5码')
        self.generate_hash(files_list)

        print('生成版本MD5码')
        self.version_md5()


if __name__ == '__main__':
    """
    脚本基本说明:
        目的: 为了验证项目主题代码和产品主体代码是否一致, 通过对每个.py文件和.sh文件生成对应的MD5码,来生成对应版本的MD5码

    使用说明:
        基础命令: python md5_encryption.py 数据收集模式 数据1 数据2 数据3 ....
            注意: 数据收集模式 和 数据 之间使用空格隔开

            数据收集模式有:
                       -D: 过滤不进行MD5码生成的文件夹
                       -d: 仅生成指定文件夹下文件的MD5码
                       -F: 过滤不进行MD5码生成的文件
                       -f: 仅对指定文件生成MD5码
                       -a: 对所有文件进行处理
                       -h: 帮助

            数据: 只需要输入文件名或文件夹名, 中间空格隔开
    """
    md5_encry = Md5Encryption(BASE_PATH)
    md5_encry.run()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值