4 from logging
import warn
6 locale
.setlocale(locale
.LC_ALL
, '')
8 warn('Error setting locale (eg. Invalid locale)')
11 from optparse
import OptionParser
13 from zeroinstall
.injector
import reader
, model
14 from zeroinstall
import support
, alias
, helpers
15 from zeroinstall
.support
import basedir
17 def export(name
, value
):
18 """Try to guess the command to set an environment variable."""
19 shell
= os
.environ
.get('SHELL', '?')
21 return "setenv %s %s" % (name
, value
)
22 return "export %s=%s" % (name
, value
)
25 """Find the first writable path in : separated list."""
27 if os
.path
.realpath(path
).startswith(basedir
.xdg_cache_home
):
28 pass # print "Skipping cache", first_path
29 elif not os
.access(path
, os
.W_OK
):
30 pass # print "No access", first_path
38 # Do this here so we can include it in the help message.
39 # But, don't abort if there isn't one because we might
40 # be doing something else (e.g. --manpage)
41 first_path
= find_path(os
.environ
['PATH'].split(':'))
43 parser
= OptionParser(usage
="usage: %%prog [options] alias [interface [command]]\n\n"
44 "Creates a script in the first usable directory in $PATH\n"
45 "(%s) to run 'interface' unless overridden by --dir.\n"
46 "If no interface is given, edits the policy for an existing alias.\n"
47 "For interfaces providing more than one command, the desired command\n"
48 "may also be given." % first_path
)
49 parser
.add_option("-m", "--manpage", help="show the manual page for an existing alias", action
='store_true')
50 parser
.add_option("-r", "--resolve", help="show the URI for an alias", action
='store_true')
51 parser
.add_option("-V", "--version", help="display version information", action
='store_true')
52 parser
.add_option("-d", "--dir", help="install in DIR", dest
="user_path", metavar
="DIR")
53 parser
.disable_interspersed_args()
55 (options
, args
) = parser
.parse_args()
59 print "0alias (zero-install) " + zeroinstall
.version
60 print "Copyright (C) 2009 Thomas Leonard"
61 print "This program comes with ABSOLUTELY NO WARRANTY,"
62 print "to the extent permitted by law."
63 print "You may redistribute copies of this program"
64 print "under the terms of the GNU Lesser General Public License."
65 print "For more information about these matters, see the file named COPYING."
70 os
.execlp('man', 'man', *args
)
73 if len(args
) < 1 or len(args
) > 3:
76 alias_prog
, interface_uri
, main
= (list(args
) + [None, None])[:3]
78 if options
.resolve
or options
.manpage
:
79 if interface_uri
is not None:
84 first_path
= options
.user_path
85 if not os
.path
.isdir(first_path
):
86 print >>sys
.stderr
, "Directory '%s' does not exist." % first_path
89 if interface_uri
is None:
91 if not os
.path
.isabs(alias_prog
):
92 full_path
= support
.find_in_path(alias_prog
)
94 raise alias
.NotAnAliasScript("Not found in $PATH: " + alias_prog
)
96 full_path
= alias_prog
98 interface_uri
, main
= alias
.parse_script(full_path
)
99 except alias
.NotAnAliasScript
, ex
:
101 os
.execlp('man', 'man', *args
)
102 print >>sys
.stderr
, str(ex
)
105 interface_uri
= model
.canonical_iface_uri(interface_uri
)
112 sels
= helpers
.ensure_cached(interface_uri
)
117 selected_impl
= sels
.selections
[interface_uri
]
119 from zeroinstall
.injector
.iface_cache
import iface_cache
120 impl_path
= selected_impl
.local_path
or iface_cache
.stores
.lookup(selected_impl
.id)
123 main
= selected_impl
.main
125 print >>sys
.stderr
, "No main program for interface '%s'" % interface_uri
128 prog_name
= os
.path
.basename(main
)
129 alias_name
= os
.path
.basename(args
[0])
133 # TODO: the feed should say where the man-pages are, but for now we'll accept
134 # a directory called man in some common locations...
135 for mandir
in ['man', 'share/man', 'usr/man', 'usr/share/man']:
136 manpath
= os
.path
.join(impl_path
, mandir
)
137 if os
.path
.isdir(manpath
):
138 # Note: unlike "man -M", this also copes with LANG settings...
139 os
.environ
['MANPATH'] = manpath
140 os
.execlp('man', 'man', prog_name
)
143 # No man directory given or found, so try searching for man files
146 for root
, dirs
, files
in os
.walk(impl_path
):
148 if f
.endswith('.gz'):
149 manpage_file
= f
[:-3]
152 if manpage_file
.endswith('.1') or \
153 manpage_file
.endswith('.6') or \
154 manpage_file
.endswith('.8'):
155 manpage_prog
= manpage_file
[:-2]
156 if manpage_prog
== prog_name
or manpage_prog
== alias_name
:
157 os
.execlp('man', 'man', os
.path
.join(root
, f
))
160 manpages
.append((root
, f
))
162 print "No matching manpage was found for '%s' (%s)" % (alias_name
, interface_uri
)
164 print "These non-matching man-pages were found, however:"
165 for root
, file in manpages
:
166 print os
.path
.join(root
, file)
169 if first_path
is None:
170 print >>sys
.stderr
, ("No writable non-cache directory in $PATH, which currently contains:\n\n%s\n\n"
171 "To create a directory for your scripts, use these commands:\n"
174 "or specify a writable path with --path"
175 % ('\n'.join(os
.environ
['PATH'].split(':')), export('PATH', '$HOME/bin:$PATH')))
179 os
.execlp('0launch', '0launch', '-gd', '--', interface_uri
)
183 interface
= model
.Interface(interface_uri
)
184 if not reader
.update_from_cache(interface
):
185 print >>sys
.stderr
, "Interface '%s' not currently in cache. Fetching..." % interface_uri
186 if os
.spawnlp(os
.P_WAIT
, '0launch', '0launch', '-d', interface_uri
):
187 raise model
.SafeException("0launch failed")
188 if not reader
.update_from_cache(interface
):
189 raise model
.SafeException("Interface still not in cache. Aborting.")
191 script
= os
.path
.join(first_path
, alias_prog
)
192 if os
.path
.exists(script
):
193 raise model
.SafeException("File '%s' already exists. Delete it first." % script
)
195 except model
.SafeException
, ex
:
196 print >>sys
.stderr
, ex
199 wrapper
= file(script
, 'w')
200 alias
.write_script(wrapper
, interface_uri
, main
)
202 # Make new script executable
203 os
.chmod(script
, 0111 | os
.fstat(wrapper
.fileno()).st_mode
)
206 print "Created script '%s'." % script
207 print "To edit policy: 0alias %s" % alias_prog
208 print "(note: some shells require you to type 'rehash' now)"