Desi Programmer @ Work

Simple and Effective Uploading with Python Script and PSCP

Sometimes you want your File Transfer tool to map certain folders on your dev machine to remote folders on your different remote machines. Wouldn't it be great if you could choose a particular file in your project, click it and it automatically uploads in appropriate folder on desired server?

For instance I have an XP dev machine with a project in folder "D:\workspace\saima" and another in "D:\workspace\ismspk". I would like all files in any sub-directory in "saima" to upload on my server "saima" in the appropriate sub-directory in "/home/saima/workspace/". Same goes for rest of my projects and servers. Of course I'd like to do it with a simple click rather than choosing the sessions and folders in my FTP client every time I make a change in a file.

I tried such an option with FileZilla and WinSCP but couldn't find any such option (maybe there exists one). So I thought about writing my own. Since I'm running XP with RSA keys setup with pageant, pscp (Putty SCP Client) was a good choice. Though other command-line utilities such as rsync etc. may do the job pretty as well.

I wrote a small Python script which I linked to my "Send To" menu. To add something in your Send-To menu, goto run, type "sendto" and create a new link here. I created a link to my Python Script and named it "Upload".

UPDATE: For Windows 7, type "shell:sendto" in your explorer bar to make a Send-To shortcut

Here is how it looks like

PSCP Sendto

Here is the Python script I wrote

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
"""
Author: Sharjeel Ahmed Qureshi
Description: Script for uploading files via pscp
You need to setup putty sessions and your RSA keys first.
Make sure that pageant is running and pscp is in your PATH variable.
Works for windows only
You are free to use this script anyway you like
"""

from os import path, popen
import sys

import logging
logger = logging
logger.basicConfig(level=logging.DEBUG)

FILES_TO_UPLOAD = sys.argv[1:]

# PATH_RULES is a config variable which is list of path rules
# Each path rule is a list of three members:
#    ['Local Drive + Directory', 'putty session name', 'remote directory']
# e.g.
# PATH_RULES = [
#    ['d:/workspace/saima/', 'saima', '/home/saima/workspace/'],
#    ['d:/workspace/smsfriends/', 'facebooksms', '/home/fbsms/public_html/www/smsfriends/'], ]

try:
    PATH_RULES = [
        # ['localdir', 'puttysession', 'remote_dir'],
        ]

    for i in PATH_RULES: i[0] = path.abspath(i[0]).lower()
    if not PATH_RULES: raise Exception("No rules defined!")
except Exception, e:
    logging.exception("There was an loading the config. Check your rules: %s" % e.message)

def err(msg):
    logging.error(msg)
    sys.stderr.write(msg + '\n')

def match_server(filename):
    """ Gets matching server for a given filename including fullpath """
    global PATH_RULES
    filename = path.abspath(filename).lower()
    for r in PATH_RULES:
        if path.dirname( filename ).startswith( r[0] ):
            psession = r[1]
            r_path = r[2] + filename.rsplit(r[0],1)[1].replace('\\', '/')
            return (psession, r_path)
    return None

def upload(filename):

    if path.isdir(filename):
        err("Directory Upload is currently not supported")

    server = match_server(filename)
    if not server:
        err("No rule available about uploading this file")
        return
    psession, r_path = server
    cmd = "pscp %s %s:%s" % (filename, psession, r_path)
    # logger.debug("Executing command %s" % cmd)
    print cmd
    print popen(cmd).read()

for f in FILES_TO_UPLOAD:
    try:
        upload(f)
    except:
        logging.exception("Error while uploading %s" % f)

raw_input("Press ENTER to Continue")