#!/usr/bin/python
import ConfigParser
import string
import sys
import os
import stat
import time
import re
from ftplib import FTP
#
# Generate a list of files but exclude certain directories/files based on
# exclude_dirs_re and exclude_file_re regular expressions.
#
def gen_file_list(base_dir, exclude_dirs_re, exclude_files_re):
names = os.listdir(base_dir)
# Removed files/directories that match exclude patterns
for i in range(len(names) - 1, 0, -1):
name = names[i - 1]
if os.path.isdir(os.path.join(base_dir, name)):
if (re.search(exclude_dirs_re, os.path.join(base_dir, name))):
names.remove(name)
if os.path.isfile(os.path.join(base_dir, name)):
if (re.search(exclude_files_re, os.path.join(base_dir, name))):
names.remove(name)
yield base_dir, names
for name in names:
if os.path.isdir(os.path.join(base_dir, name)):
for (newbase_dir, children) in \
gen_file_list(os.path.join(base_dir, name), \
exclude_dirs_re, exclude_files_re):
yield newbase_dir, children
#
# Connect to an ftp server using provided username/password
#
def ftp_connect(server, username, password):
ftp = FTP(server)
ftp.login(username,password)
return ftp
#
# Disconnect from an ftp object
#
def ftp_disconnect(ftp):
ftp.quit()
#
# Check if a directory exists on the ftp server
#
def ftp_check_if_dir_exists(ftp, remote_file):
# Theory: Save current directory, change directory into any necessary
# sub-directory, get directory listing, see if directory exists,
# change directory back to original directory.
old_pwd = ftp.pwd();
rootdir = os.path.dirname(remote_file)
dirname = os.path.basename(remote_file)
ftp.cwd(rootdir)
dir_listing = []
ftp.retrlines('LIST', dir_listing.append)
ret = False
for line in dir_listing:
words = string.split(line, None, 8)
filename_to_compare = string.lstrip(words[-1])
# a directory listing should begin with d
if (words[0][0] == 'd'):
if (filename_to_compare == dirname):
ret = True
ftp.cwd(old_pwd)
return ret
#
# Upload a file or create a directory on an ftp server.
#
def ftp_upload_file(ftp, local_file, remote_file):
if os.path.isdir(local_file):
if not ftp_check_if_dir_exists(ftp, remote_file):
print "creating directory: %s" % remote_file
ftp.mkd(remote_file)
if os.path.isfile(local_file):
# get remote file's modification time
remote_mtime = ftp.sendcmd("MDTM " + remote_file)
# strip ftp response number do-dad from modificaiton time
remote_mtime = remote_mtime.split(' ')[1]
# get local file's modifcation time taking into account that the
# ftp server's mtime may not be in UTC format. It is added to our
# localtime insead for comparison
utc_offset = string.atoi(config.get("ftp", "utc_offset"))
mtime = time.gmtime(os.stat(local_file).st_mtime)
local_mtime = "%4d%2d%2d%2d%2d%2d" % (mtime.tm_year, mtime.tm_mon, mtime.tm_mday, mtime.tm_hour + utc_offset, mtime.tm_min, mtime.tm_sec);
local_mtime = local_mtime.replace(' ', '0');
if (local_mtime > remote_mtime):
print "uploading %s" % remote_file
fd = open(local_file, "rb")
ftp.storbinary("STOR " + remote_file, fd)
fd.close()
#
# Function to upload a website to web server via ftp
#
def ftp_upload_site():
do_upload = raw_input("Would you like to upload your website? (y/n): ")
if ((do_upload != 'y') and (do_upload != 'Y')):
print "Not uploading site at this time as specified by user"
sys.exit(1)
server = config.get("ftp", "ftp_server")
username = config.get("ftp", "ftp_username")
try:
password = config.get("ftp", "ftp_password")
except:
password = raw_input("Please enter your ftp password for %s at %s : " %
(username, server))
sys.exit(1)
try:
exclude_dirs_re = config.get("ftp", "ftp_exclude_dirs")
except:
exclude_dirs_re = ""
try:
exclude_files_re = config.get("ftp", "ftp_exclude_files")
except:
exclude_files_re = ""
p = re.compile("(\s)?,(\s)?")
exclude_dirs_re = "^" + p.sub("$|^", exclude_dirs_re) + "$"
exclude_files_re = "^" + p.sub("$|^", exclude_files_re) + "$"
ftp = ftp_connect(server, username, password)
for (basepath, children) in gen_file_list(".", exclude_dirs_re, exclude_files_re):
for child in children:
local_file = os.path.join(basepath, child)
remote_file = local_file.lstrip('./')
ftp_upload_file(ftp, local_file, remote_file)
ftp_disconnect(ftp)
#
# Main code entry point
#
# Make sure we have 2 args
if len(sys.argv) < 3:
print "Error:\n Usage: %s <.conf file> " % sys.argv[0]
sys.exit(1)
# Get cmdline options
conf_file = sys.argv[1]
input_dir = sys.argv[2]
# Make sure .conf file exists
if not os.path.isfile(conf_file):
print "Error\n <.conf file> %s does not exist" % conf_file
sys.exit(1)
# Make sure input directory exists
if not os.path.isdir(input_dir):
print "Error\n %s does not exist" % input_dir
sys.exit(1)
config = ConfigParser.ConfigParser()
config.read(conf_file)
# Use this prefix to match strings in the html file.
# For instance, if your configuration file is:
# [general]
# html_tag_prefix:auto
# [header]
# html:test
#
# Then placing will be replaced with
# test
try:
prefix = config.get("general", "html_tag_prefix")
except:
print "Error: [general]->html_tag_prefix must be "\
"defined in the configuration file."
sys.exit(1)
sed_opts = ""
# Create "full-names" for each section-option pair. These are the strings which
# will be replaced in the html files as described above.
for section in config.sections():
for option in config.options(section):
key_name = "<" + prefix + "_" + section + "_" + option + ">"
key_data = config.get(section, option)
# delimit newlines and backslashes for sed
key_data = "\/".join(key_data.split("/"))
key_data = "\\n ".join(key_data.split("\n"))
sed_opts += " -e \'s/%s/%s/g\' " % (key_name, key_data)
# Use sed to modify all files in the input directory. Note that this is not
# recursive at this point
for file in os.listdir(input_dir):
full_path = os.path.join(input_dir,file)
if os.path.isfile(full_path):
print "Generating " + file
cmd = "sed %s %s > %s" % (sed_opts, full_path, file)
os.system(cmd)
#
# Go ahead and upload the site!
#
ftp_upload_site()