`
xieye
  • 浏览: 836039 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

利用python的ftp客户端自动更新文件

阅读更多
问题的提出:

开发笔记本(windows),测试服务器(linux)都在办公室,远程服务器在远程(系统随便)。

原本使用svn更新代码,而且svn跨平台。开发机和测试机都安装了,但是远程不允许装任何程序,只有ftp帐号,别的神马都没有。

怎么更新代码呢?当然可以手动更新,但是程序员喜欢自动化。于是有如下python代码来实现自动化操作。

具体步骤,首先开发机修改代码,然后测试机更新,更新的同时需另外写程序(我用php)来把svn的更新记录搞到一张mysql的表里(其实文件也行),搞表里的操作是自动的。

然后测试机如果测试通过,需要部署到远程上,只需在测试机上执行python /.../.../svnupdate.py即可

目前的程序缺点:中文文件名和文件夹名貌似不支持

注意事项,
1、php程序和python程序都跑在测试机上,是linux,需要php和python和svn安装环境,并且php需要root身份或能执行system命令的身份,程序中执行了svn info等linux命令
2、假定程序在/www/code下,而ftp的服务端根路径是/www,所以需要把/www去掉再做ftp操作。


两张表,一张只放svn版本号,测试机每更新一次就自动记录最新版本号。
另一张记录svn的具体历史。
CREATE TABLE `svn_version` (
  `value` int(11) NOT NULL default 0 COMMENT 'svn当前版本'
) ENGINE=MyISAM DEFAULT CHARSET=utf8;


CREATE TABLE `svn_history` (
  `id` int(11) NOT NULL auto_increment COMMENT '主键id',
  `author` varchar(255) NOT NULL default '' COMMENT '原作者',
  `operate` varchar(255) NOT NULL default '' COMMENT '操作,通常是A,M,D中的一个',
  `svn_version` int not null default 0 comment '版本号',
  `filename`    varchar(255) not null default '' comment '文件名或文件夹名',
  `created_at` int(11) NOT NULL default 0 COMMENT '创建时间',
   hasprocess int not null default 0 comment '是否处理过,默认未处理',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;



python初哥的svnupdate.py代码如下
#-*- coding:utf-8 -*-

# 例:FTP编程 
#
# 功能统计
#  1)创建文件夹
#  2)添加文件
#  3)覆盖(修改文件) 注:就是添加,因为添加默认就是覆盖文件
#  4)删除文件
#  5)删除文件夹(级联删除)
# 
#  
#  
# 首先:测试客户机有个svn_history表,每次测试客户机更新时会把svn的记录加到表里 
#  
#  
from ftplib import FTP 
import re
import platform
import MySQLdb


def get_folder_arr(ftp, name, arr={}):
    ftp.cwd(name)
    list = ftp.nlst()
    for subname in list:
        new_name = join_name(name, subname)
        arr[new_name]={}
        if is_folder(subname):
            get_folder_arr(ftp, new_name, arr[new_name])
    return arr

def get_folder_arr_simple(ftp, name):
    arr=[]
    ftp.cwd(name)
    list = ftp.nlst()
    for subname in list:
        new_name = join_name(name, subname)
        arr.append(new_name)
    return arr

def get_folder_arr_simple_no_fullname(ftp, name):
    arr=[]
    ftp.cwd(name)
    list = ftp.nlst()
    for subname in list:
        arr.append(subname)
    return arr


def join_name(folder_name, file_name):
    return folder_name + '/' + file_name

def get_left_from_fullname(name):
    match = re.search("^(.+)/[^/]+$", name)
    return match.group(1)

def get_right_from_fullname(name):
    match = re.search("^.+/([^/]+)$", name)
    return match.group(1)
    

def is_folder_in_fullname(name):
    return is_folder(get_right_from_fullname(name))

def is_file_in_fullname(name):
    return is_file(get_right_from_fullname(name))


def is_folder(name):
    if len(name)==1: return True   
    if re.match("^.[^.]+$", name): # 除了开头,全部不带点的就是文件夹,还有1个字符我也认为是文件夹
        return True
    else:
        return False

def is_file(name):
    return not is_folder(name)

def is_empty_folder(ftp,name):
    ftp.cwd(name)
    list=ftp.nlst()
    if len(list) == 0:
        return True
    else:
        return False
    
# 删除文件夹的方法是,先清空里面全部(文件和文件夹),再删除本身    
def del_folder(ftp,name):
    arr = get_folder_arr_simple(ftp, name)
    # 现在开始递归
    for key in arr:
        if is_folder_in_fullname(key) : # 删文件夹
            del_folder(ftp, key)
        else:        # 否则删除文件
            file_name = get_right_from_fullname(key)
            folder_name  = get_left_from_fullname(key)
            ftp.cwd(folder_name)
            ftp.delete(file_name) 
    folder_name = get_right_from_fullname(name)
    parent_folder_name  = get_left_from_fullname(name)
    ftp.cwd(parent_folder_name)
    ftp.rmd(folder_name)             


def get_ftp():
    ftp = FTP() 
    port = 21 
    
    # 连接FTP服务器
    ftp.connect('www.example.net',port) 
    user = 'username'
    passwd = 'passwd'
    # 登录 
    ftp.login(user, passwd)
    return ftp

def cut_www(name):
    match = re.search("^/www(.+)$", name)
    return match.group(1)

# 公开接口,创建文件夹,参数类似/www/code/web/11,假设11是文件夹
def public_mkdir(ftp, dir_name):
    windows2003_name = cut_www(dir_name)
    try:
        ftp.mkd(windows2003_name)
    except:
        pass
    
    
def public_add_and_update_file(ftp, file_name):
    windows2003_name =  cut_www(file_name)
    try:
        ftp.cwd(get_left_from_fullname(windows2003_name))
        # 准备上传文件
        file_handler = open(file_name, 'rb')
        ftp.storbinary('STOR '+ get_right_from_fullname(windows2003_name), file_handler)
        file_handler.close()
    except:
        pass
 
 
def public_del_file_and_folder(ftp, name):
    windows2003_name =  cut_www(name)
    # 判断是否存在
    try:
        realname = get_right_from_fullname(windows2003_name)
        parent_folder = get_left_from_fullname(windows2003_name)
        arr = get_folder_arr_simple_no_fullname(ftp, parent_folder)
        if realname in arr:
            if is_file(realname):
                ftp.cwd(parent_folder)
                ftp.delete(realname)
            else:
                del_folder(ftp, windows2003_name)    
    except:
        pass

    

def query_by_sql(sql):
    conn  = MySQLdb.Connect ( \
        host = 'localhost', 
        user = 'root',
        passwd = '1', 
        db = 'www', 
        charset="utf8",
    )
    cursor = conn.cursor( cursorclass = MySQLdb.cursors.DictCursor )
    
    cursor.execute( sql )
    rows = cursor.fetchall()
    cursor.close()
    conn.close()
    return rows

def execute_by_sql(sql):
    conn  = MySQLdb.Connect ( \
        host = 'localhost', 
        user = 'root',
        passwd = '1', 
        db = 'www', 
        charset="utf8",
    )
    cursor = conn.cursor( cursorclass = MySQLdb.cursors.DictCursor )
   
    cursor.execute( sql )
    conn.commit()
    cursor.close()
    conn.close()


def main_program():
    ftp = get_ftp()
    # 打印欢迎信息 
    print ftp.getwelcome() 
    
    arr = query_by_sql("select * from svn_history where hasprocess=0 order by id asc")
    for row in arr:
        name = row['filename']
        operate = row['operate']
        print operate + ' ' + name
        if operate == 'A':
            if is_folder_in_fullname(name):
                public_mkdir(ftp, name)
            else:
                public_add_and_update_file(ftp, name)
        if operate == 'M':
            public_add_and_update_file(ftp, name)
        if operate == 'D':
            public_del_file_and_folder(ftp, name)
        execute_by_sql("update svn_history set hasprocess=1 where id =" + str(row['id']))                    
    ftp.quit() 
    # 退出FTP服务器

main_program()



自动化的加到表里的php代码是
<?php 
  
/**
 * 该php程序会查询svn,并得到最新版本号,然后存入到表svn_version里
 * 
 * 
 * 2010-11-26
 */

include('CommandPublic.php'); //这只是为了数据库查询等,关系不大

define('target', '/www/data/log/svnhistory.txt');

//这是svn的版本库在本机的拷贝路径
define('defined_dir', '/www/code');

/**
 * 获得版本号
 *
 * @return unknown
 */
function get_svn_version(){
    $target_log = '/www/data/log/svnlog.txt';
    $command = 'svn info /www/code/ > ' . $target_log;
    
    system($command);
    $command = "chmod 777 " . $target_log;
    system($command);
    
    $version = '';
    $arr = file($target_log);
    foreach ($arr as $value) {
        $value = preg_replace('/\n|\r\n/','',$value);
        if (preg_match('/^修订版:\d+$/', $value)) {
            $version = preg_replace('/^修订版:(\d+)$/','$1', $value);
            break;
        }
        
    }
    return intval($version);
}

/**
 * 对于每个版本,都要把里面的若干条记录插到数据库的表svn_history
 * 
 * 若干条的意思是一条或多条
 *
 * @param int $version
 */
function set_version($version) 
{
    $db = Sys::getdb();
    //首先获取信息
    $version = intval($version);
    $command ='svn log -v -r '. $version.' /www/code >  '.target;
    system($command);
    $arr = file(target);
    
    $line ='';
    //这个循环实际只为获取一句话
    //类似如下
    //r2525 | xieye | 2011-02-09 15:22:46 +0800 (三, 09  2月 2011) | 1 line
    foreach ($arr as $value) {
        if (preg_match('/^r\d+/', $value)) {
            $line = $value;
            break;
        }
    }
    
    $author =trim(preg_replace('/^.+\\|(.+)\\|.+\\|.+$/', '$1', $line));
    
    //现在获取文件修改历史
    foreach ($arr as $value) {
        $value = preg_replace('/\n|\r\n/','', $value);
        
        if (preg_match('/^\s+[A-Z]\s+.+$/s', $value)) {
            $operate = preg_replace('/^\s+([A-Z])\s+.+$/s', '$1', $value);
            $file = preg_replace('/^\s+[A-Z]\s+(.+)$/s', '$1', $value);
            $obj = new DatabaseObject_SvnHistory(); //用这个类意义不大,仅仅是插一条记录,也可以直接写sql
            $obj->svn_version =$version ;
            $obj->filename =defined_dir . $file;
            $obj->author =$author;
            $obj->created_at =get_current_time();
            $obj->hasprocess =0;
            $obj->operate =$operate;
            $obj->save();
        }
    }
}

/**
 * 获取一个固定时间
 *
 * @return int
 */
function get_current_time()
{
    static $time=null;
    if ($time==null) {
        $time=time();
    }
    return $time;
}

$db = Sys::getdb();

//首先取得老的版本号
$sql = "select value from  svn_version";
$old_version =  intval($db->fetchOne($sql));


$version = get_svn_version();
$sql = "update svn_version set value={$version} ";
$db->query($sql);


//如果相等就什么也不做。注意这些代码都跑在linux服务器上。
if ($version == $old_version) {
    exit;
}

//否则,就需要从老版本加1开始,一直做到最新的版本。
for ($i = $old_version +1; $i <= $version; $i++) {
    set_version($i);
}

echo "\n数据库里的svn版本已更新。\n";
?>


分享到:
评论

相关推荐

    基于java+springboot+mysql+微信小程序的流浪动物救助小程序 源码+数据库+论文(高分毕业设计).zip

    项目已获导师指导并通过的高分毕业设计项目,可作为课程设计和期末大作业,下载即用无需修改,项目完整确保可以运行。 包含:项目源码、数据库脚本、软件工具等,该项目可以作为毕设、课程设计使用,前后端代码都在里面。 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值。 项目都经过严格调试,确保可以运行!可以放心下载 技术组成 语言:java 开发环境:idea、微信开发者工具 数据库:MySql5.7以上 部署环境:maven 数据库工具:navicat

    基于springboot的体质测试数据分析及可视化设计源码(java毕业设计完整源码+LW).zip

    项目均经过测试,可正常运行! 环境说明: 开发语言:java JDK版本:jdk1.8 框架:springboot 数据库:mysql 5.7/8 数据库工具:navicat 开发软件:eclipse/idea

    python 3.8.20 windows install 安装包

    编译的 python 3.8.20 windows install 安装包

    基于go-zero的用户管理系统全部资料+详细文档.zip

    【资源说明】 基于go-zero的用户管理系统全部资料+详细文档.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    基于springboot的时间管理系统源码(java毕业设计完整源码+LW).zip

    时间管理系统采用java技术,基于springboot框架,mysql数据库进行开发,实现了首页,个人中心,系统公告管理,用户管理,时间分类管理,事件数据管理,目标数据管理,用户日记管理等内容进行管理。 环境说明: 开发语言:java JDK版本:jdk1.8 框架:springboot 数据库:mysql 5.7/8 数据库工具:navicat 开发软件:eclipse/idea

    基于springboot的火车订票管理系统源码(java毕业设计完整源码+LW).zip

    项目均经过测试,可正常运行! 环境说明: 开发语言:java JDK版本:jdk1.8 框架:springboot 数据库:mysql 5.7/8 数据库工具:navicat 开发软件:eclipse/idea

    收到防护服快快快啊啊啊啊啊

    收到防护服快快快啊啊啊啊啊

    葡萄城手册,快速上手,灵活报表

    制作报表

    simulink相位调制器PM

    simulink相位调制器PM

    2023-04-06-项目笔记 - 第三百六十阶段 - 4.4.2.358全局变量的作用域-358 -2025.12.27

    2023-04-06-项目笔记-第三百六十阶段-课前小分享_小分享1.坚持提交gitee 小分享2.作业中提交代码 小分享3.写代码注意代码风格 4.3.1变量的使用 4.4变量的作用域与生命周期 4.4.1局部变量的作用域 4.4.2全局变量的作用域 4.4.2.1全局变量的作用域_1 4.4.2.358局变量的作用域_358- 2024-12-27

    (59423620)指纹识别基于matlab GUI指纹识别【含Matlab源码 1353期】.zip

    【指纹识别】基于matlab GUI指纹识别是一种生物特征识别技术,它利用了人类指纹的唯一性和稳定性进行身份验证。在本项目中,我们探讨的是如何使用MATLAB图形用户界面(GUI)来实现这一过程,包括图像采集、预处理、特征提取和匹配等多个步骤。 指纹图像的采集是整个系统的基础。这通常通过专用的指纹传感器完成,它们可以捕获高质量的指纹图像。在MATLAB中,我们可以使用摄像头或其他图像输入设备模拟这一过程,将捕获的图像导入到GUI中。 接下来是预处理阶段。指纹图像往往含有噪声和不清晰的部分,因此需要进行图像增强,以突出指纹的细节特征,如脊线和谷线。这可能包括二值化、直方图均衡化、滤波等操作。MATLAB的图像处理工具箱提供了丰富的函数支持这些预处理步骤。 特征提取是识别的核心环节。指纹的特征通常包括核心点、三角点、终结点以及脊线的方向和纹路模式。MATLAB中可以使用方向图像和细化算法来检测这些特征点,并生成特征描述符。例如,使用Gabor滤波器可以提取脊线方向信息,而细化算法可以帮助找到特征点。 GUI设计是用户交互的关键。在这里,用户可以上传指纹图像,系统会实时显示预处理和特征提取的

    基于Go后端的外挂式评论系统全部资料+详细文档.zip

    【资源说明】 基于Go后端的外挂式评论系统全部资料+详细文档.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    nosql分布式数据库期末考试题a.docx

    ### NoSQL分布式数据库知识点解析 #### 一、选择题知识点详解 **1. 关系数据库与非关系数据库** - **关系数据库**: MySQL、SQL Server 和 Oracle 均属于关系数据库,它们采用 SQL 作为标准查询语言,支持 ACID 特性(原子性、一致性、隔离性和持久性)。 - **非关系数据库**: 指的是不采用表格形式来组织数据的数据库类型,通常用于处理大量非结构化或半结构化数据。 **2. 数据库语言分类** - **数据定义语言 (DDL)**: 用于定义数据库结构的语言,如创建、修改和删除表等操作。 - **数据操纵语言 (DML)**: 用于添加、修改和删除数据的语言,如 INSERT、UPDATE 和 DELETE 等命令。 - **数据查询语言 (DQL)**: 用于查询数据的语言,主要是 SELECT 语句。 - **数据控制语言 (DCL)**: 用于管理权限和安全性的语言,如 GRANT 和 REVOKE 命令。 **3. 关系数据库优点** - **易于理解**: 使用表格形式组织数据,符合人类直观认知习惯。 - **易于维护**: 支持事务处理,确保数据一致性。 - **支持 SQL**: 使用标准查询语言,便于数据查询和处理。 **4. MongoDB 编程语言** - **JavaScript**: MongoDB 是用 C++ 开发的,但其 Shell 环境使用 JavaScript,使得数据查询和管理更加便捷。 **5. NoSQL 数据库特点** - **分布式**: 能够在多台计算机上分布存储数据,适用于大数据量的处理。 - **不基于 ACID**: 相对于传统的关系数据库,NoSQL 数据库往往牺牲了部分 ACID 特性以换取更高的性能和可扩展性。 **6. CAP 理论** - **一致性 (C)**: 所有节点在同一时间具有相同的数据。 - **可用性 (A)**: 每个请求都能得到一个合理的时间内非错误的响应,但不保证是最新的数据。 - **分区容错性 (P)**: 系统中任意信息丢失的子网故障都不会导致整个系统不可用。 - **CAP 定理**: 在一个分布式系统中,只能同时满足一致性、可用性和分区容错性中的两个。 **7. 知识图谱与 NoSQL 数据库** - **MongoDB**: 适合用于构建知识图谱,因为它支持灵活的数据模型和高效的查询能力。 - **Redis**: 一种键值存储数据库,适用于缓存和实时数据分析。 - **HBase**: 一种列族存储数据库,适合大规模随机读写访问。 **8. HBase 特点** - **容量巨大**: 可以存储非常大量的数据。 - **列存储**: 数据按列族存储,方便进行列级别的访问。 - **稀疏性**: 允许某些列未填充,即某些单元格为空。 **9. HBase 核心组件** - **HMaster**: 负责协调客户端请求、分配 Region 以及负载均衡等工作。 - **RegionServer**: 存储数据的实际服务器。 - **Zookeeper**: 用于协调分布式环境中的服务,例如选举 HMaster。 **10. MongoDB 集合命名规则** - **system.**: 系统保留前缀,用于系统集合。 - **保留字符 $**: 用于特殊目的,如聚合管道。 - **空字符串**: 不允许作为集合名称。 **11. MongoDB 主键** - **UUID**: 通用唯一识别码,常用于作为主键。 - **Sequence**: 序列,也可以作为主键生成方式之一。 - **Auto-increment**: 自动递增,MongoDB 默认为主键使用 BSON 类型的 ObjectId。 **12. MongoDB 逻辑结构** - **数据库 (db)**: MongoDB 中的最高层级,可以包含多个集合。 - **集合 (collection)**: 数据库内的数据容器,类似于关系数据库中的表。 - **文档 (document)**: 数据的基本单位,由键值对组成。 **13. 内存数据库** - **Redis**: 键值存储数据库,常作为内存数据库使用。 - **MongoDB**: 非内存数据库,但可以通过配置将常用数据驻留在内存中。 - **Bigtable**: 谷歌的分布式数据存储系统,并非专门设计为内存数据库。 **14. Neo4j 图形数据库应用场景** - **快递物流数据管理**: 适用于关系较为复杂的数据管理场景。 - **家庭用电数据管理**: 更偏向于使用时序数据库。 - **企业考勤数

    双工位多吸嘴龙门式取放模块proe5.0可编辑全套技术资料100%好用.zip

    双工位多吸嘴龙门式取放模块proe5.0可编辑全套技术资料100%好用.zip

    主持稿22222222222

    主持稿22222222222

    基于ssm的模拟麦当劳点餐系统全部资料+详细文档.zip

    【资源说明】 基于ssm的模拟麦当劳点餐系统全部资料+详细文档.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

    php.html.mysql.zip

    php.html.mysql.zip

    Java 入门教程.md

    Java 入门教程.md

    CD668cb芯片电路图

    CD668cb芯片电路图

    基于C语言课程设计大作业 - 马里奥游戏、详细文档+全部资料+高分项目.zip

    【资源说明】 基于C语言课程设计大作业 - 马里奥游戏、详细文档+全部资料+高分项目.zip 【备注】 1、该项目是个人高分项目源码,已获导师指导认可通过,答辩评审分达到95分 2、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 3、本项目适合计算机相关专业(人工智能、通信工程、自动化、电子信息、物联网等)的在校学生、老师或者企业员工下载使用,也可作为毕业设计、课程设计、作业、项目初期立项演示等,当然也适合小白学习进阶。 4、如果基础还行,可以在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!

Global site tag (gtag.js) - Google Analytics