设为首页 收藏本站
查看: 1459|回复: 0

[经验分享] 利用python的ftp客户端自动更新文件

[复制链接]

尚未签到

发表于 2016-6-9 13:11:45 | 显示全部楼层 |阅读模式
问题的提出:
开发笔记本(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";
?>

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-228290-1-1.html 上篇帖子: java 实现ftp的文件上传和删除 下篇帖子: Kettle实践--从FTP上取文件,再放至另一个FTP上
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表