Welcome, guest | Sign In | My Account | Store | Cart

This program expands upon my Do.py program (Recipe: 577439). Instead of doing one expansion for the entire comand, it performs an expansion on each argument. It uses the Do.py program preserving macro definitions.

Python, 150 lines
  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
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# ----------------------------------------------
# Name: Do2
# Description: Expand and execute command
## D20H-35 Expand and execute command
#
# Author: Philip S. Rist
# Date: 10/24/2010
# Copyright 2010 by St. Thomas Software
# ----------------------------------------------
# This program is freeware.  It may be used
# for any moral purpose.  You use it at your
# own risk.  St. Thomas Software makes no
# guarantees to its fitness to do anything.
#
# If you feel you must pay for it. Please
# send one million dollars to
#
#     The International Rescue Committee
#     122 East 42nd Street
#     New York, N.Y.   10168-1289
#
# Ok, we are in a recession.  So, make it a half
# million.

# Usage examples:
#
#[HKEY_CLASSES_ROOT\*\Shell\Do2Bkup]
#@="Backup (Do2)"
#"EditFlags"=hex:01,00,00,00
#[HKEY_CLASSES_ROOT\*\Shell\Do2Bkup\Command]
#@="c:\\sys\\python25\\pythonw.exe c:\\bin\\do2.py \"%1\" c:\\Windows\\system32\\cmd.exe /K copy \"{a}\" \"{u}\\{2}\\{f}\"      "
#
#[HKEY_CLASSES_ROOT\*\Shell\Do2Edit]
#@="Edit (Do2)"
#"EditFlags"=hex:01,00,00,00
#[HKEY_CLASSES_ROOT\*\Shell\Do2Edit\Command]
#@="c:\\sys\\python25\\pythonw.exe c:\\bin\\do2.py \"%1\" c:\\Source\\{2}\\qeditor.exe  \"{a}\"     "
#


import sys, getopt, os
import Do
import subprocess

def ParentSearch(pFilePath, pDefaultPath, pJoin='\\'):
    '''
    Scan parent list for file selecting lowest level matching file
    '''
    lParts = pFilePath.split(pJoin)
    lCount = len(lParts) - 1
    lPath = ''
    while lCount > 0:
        lPath = pJoin.join(lParts[0:lCount]) + pJoin + lParts[-1]
        if os.path.exists(lPath):
            break
        lCount -= 1
    else:
        lPath = pDefaultPath
    return lPath

def ExpandArg(pArg, pFilePath, pDefaultPath, pLeft='{', pSep=';', pQuote='"', 
                              pPref='{<-}', pJoin='\\'):
    '''
    Expand single command line argument
    '''
#                    Expand argument   
    if pArg.find(pLeft) >= 0:
        lArg = Do.Expand(pArg, pFilePath)
    else:
        lArg = pArg

#                    If starts with {<-} and single path scan parent folders for
#                    first matching file.  Each folder above specified path will
#                    be checked until file is found.
    if lArg.startswith(pPref) and lArg.find(pSep) < 0:
        lArg = os.path.abspath(lArg[2:])
        print 'Parent Search 1'
        lArg = ParentSearch(lArg, pDefaultPath, pJoin=pJoin)

#                    If multiple paths separated by pSep(';') select first valid path
    lFound = ''
    if lArg.find(pSep) >= 0:
        lPaths = lArg.split(pSep)
        for lPath in lPaths:
            if lPath.startswith(pPref):
                lPath = os.path.abspath(lPath[4:])
                lPath = ParentSearch(lPath, pDefaultPath, pJoin=pJoin)    # 01/19/11
            if lPath == '':                                               #
                continue                                                  #
            lPath = os.path.abspath(lPath)
            if os.path.exists(lPath):
                lFound = lPath
                break
        else:
            lFound = os.path.abspath(pDefaultPath)
    else:
        lFound = lArg
    
#                    If argument contains space enclose it within quotes
    lFound = lFound.strip()
    if lFound.find(' ') > 0 and lFound[0] != pQuote:
        lFound = pQuote + lFound + pQuote
    return lFound

def submitnow(pCommand):
    '''
    Submit command
    '''
    lCommand = '"' + pCommand + '"'
    #print '\n\nSubmitting:', lCommand
    subprocess.Popen(lCommand, shell=True)



#sys.argv.extend( [ '-d', '{o}\\new', 'c:\\source\\python\\new\\do.py', 'c:\\bin\\echop.bat', 
#       '{a}', '{p}\\test\\{f}', '{<-}\\{p}\\menus.ini', '{t}\\{xx}.bkp',
#       '{i}\\{-1}', '   {u}\\{-2}', '{.}\\{-3}   ', '"{g}\\{2}\\test.{e}"', 
#       '{0}\\{3}\\{n}.{e}.txt'    ])

if __name__ == '__main__':
    (mOptions, mArgs) = getopt.getopt(sys.argv[1:], 'd:e:')
    
    mFilePath = mArgs[0]

    mDefaultPath = ''
    for (mKey, mValue) in mOptions:
        if mKey == '-d':
            if mValue.find('}'):
                mValue = ExpandArg(mValue, mFilePath, '')
            if mValue != '':
                os.chdir(mValue)
            
        elif mKey == '-e':
            setenviron(mValue, mFilePath)

        elif mKey == '-p':
            mValue = ExpandArg(mValue, mFilePath, '')
            if mValue != '':
                mDefaultPath = mValue

    mCommand = ''
    mCount = 0
    for mArg in mArgs[1:]:
        mText = ExpandArg(mArg, mFilePath, mDefaultPath) + ' '
        #print '%5d: %-24s * %-30s ---> %s' % (mCount, mArgs[mCount+1], mFilePath, mText)
        mCommand += mText
        mCount += 1

    if len(mCommand) > 0:                
        submitnow(mCommand)
    

    

Because each expansion processes one argument the program can recognize arguments with embedded white space. Quotes will be added as needed. The program will also accept an argument consisting of a series of paths separated by ';' with or without macro expansion. After expansion each path will be validated from left to right. The first to be valid will be added to the command line.

{o}\menus.ini;c:\data\{e}\menus.ini will result in

any.py selecting c:\source\Python\menus.ini
any.gif selecting c:\data\gif\menus.ini
any.txt selecting c:\bin\menus.ini the hardcoded default

A new macro was added. The macro '{<-}' at the beginning of any path will cause the program to search up the folder tree looking for an appropriatly named file. The first one found, the lowest level file will be used. The argument '{<-}{o}\new\any.py' will scan in reverse the c:\source\python\new tree for the lowest level any.py file.

The program has only been run on a Win32 XP system with Active Python 2.5 and 2.7.

1 comment

Phil Rist (author) 13 years, 2 months ago  # | flag

I found a bug. The '{<-}' macro did not work with the ';' path separators. This required two lines of code to be added. Which I have done. This feature is used in my button bar program.

I like using the context menus provided by Windows. Right clicking a folder will display a menu of programs with links to the selected folder. Initially I added programs to this menu but the list got too long. The first solution was a single entry executing my button bar program. This still meant there was only one menu for every folder.

Putting a macro within the menu name can select different menus depending on the selected folder as in '{a}\menus.ini'. The ';' allows the specification of an alternative or default menu if the first is not found as in '{a}\menus.ini;c:\bin\menus.ini'. This requires a menu in every folder for which I do not want to use the default menu. I could use '{a]\menus.ini;{p}\menus.ini;c:\bin\menus.ini' to search the current and parent folders. This is still limiting.

The '{<-}' macro will cause the path of a folder to be searched bottom up starting with the that folder until the file name is found, as in '{<-}c:\source\python\projects\menus.ini'. Combining this macro with the ';' separator allows for multiple searches and the specification of a default file as in '{<-}{a}\test.ini;{<-}{a}\menus.ini;c:\bin\menus.ini'.

I can put a menu in a high level folder such as 'c:\source\python' and access it from any sub-folder. I can also add a menu to a sub-folder if I want a different menu for that sub-folder.

Created by Phil Rist on Mon, 25 Oct 2010 (MIT)
Python recipes (4591)
Phil Rist's recipes (9)

Required Modules

Other Information and Tasks