2 # Copyright (C) 2010, Thomas Leonard
3 # See the README file for details, or visit http://0install.net.
6 from logging
import warn
8 locale
.setlocale(locale
.LC_ALL
, '')
10 warn('Error setting locale (eg. Invalid locale)')
16 from optparse
import OptionParser
18 from zeroinstall
.injector
import reader
, model
19 from zeroinstall
import support
, alias
, helpers
20 from zeroinstall
.support
import basedir
22 def export(name
, value
):
23 """Try to guess the command to set an environment variable."""
24 shell
= os
.environ
.get('SHELL', '?')
26 return "setenv %s %s" % (name
, value
)
27 return "export %s=%s" % (name
, value
)
30 """Find the first writable path in : separated list."""
32 if os
.path
.realpath(path
).startswith(basedir
.xdg_cache_home
):
33 pass # print "Skipping cache", first_path
34 elif not os
.access(path
, os
.W_OK
):
35 pass # print "No access", first_path
43 # Do this here so we can include it in the help message.
44 # But, don't abort if there isn't one because we might
45 # be doing something else (e.g. --manpage)
46 first_path
= find_path(os
.environ
['PATH'].split(':'))
47 in_path
= first_path
is not None
49 first_path
= os
.path
.expanduser('~/bin/')
51 parser
= OptionParser(usage
="usage: %%prog [options] alias [interface [main]]\n\n"
52 "Creates a script to run 'interface' (will be created in\n"
53 "%s unless overridden by --dir).\n\n"
54 "If no interface is given, edits the policy for an existing alias.\n"
55 "For interfaces providing more than one executable, the desired\n"
56 "'main' binary or command may also be given." % first_path
)
57 parser
.add_option("-c", "--command", help="the command the alias will run (default 'run')", metavar
='COMMNAD')
58 parser
.add_option("-m", "--manpage", help="show the manual page for an existing alias", action
='store_true')
59 parser
.add_option("-r", "--resolve", help="show the URI for an alias", action
='store_true')
60 parser
.add_option("-V", "--version", help="display version information", action
='store_true')
61 parser
.add_option("-d", "--dir", help="install in DIR", dest
="user_path", metavar
="DIR")
62 parser
.disable_interspersed_args()
64 (options
, args
) = parser
.parse_args()
68 print "0alias (zero-install) " + zeroinstall
.version
69 print "Copyright (C) 2010 Thomas Leonard"
70 print "This program comes with ABSOLUTELY NO WARRANTY,"
71 print "to the extent permitted by law."
72 print "You may redistribute copies of this program"
73 print "under the terms of the GNU Lesser General Public License."
74 print "For more information about these matters, see the file named COPYING."
79 os
.execlp('man', 'man', *args
)
82 if len(args
) < 1 or len(args
) > 3:
85 alias_prog
, interface_uri
, main
= (list(args
) + [None, None])[:3]
86 command
= options
.command
or 'run'
88 if options
.resolve
or options
.manpage
:
89 if interface_uri
is not None:
94 first_path
= options
.user_path
96 if interface_uri
is None:
98 print >>sys
.stderr
, "Can't use --command when editing an existing alias"
101 if not os
.path
.isabs(alias_prog
):
102 full_path
= support
.find_in_path(alias_prog
)
104 raise alias
.NotAnAliasScript("Not found in $PATH: " + alias_prog
)
106 full_path
= alias_prog
108 alias_info
= alias
.parse_script(full_path
)
109 interface_uri
= alias_info
.uri
110 main
= alias_info
.main
111 command
= alias_info
.command
112 except alias
.NotAnAliasScript
as ex
:
114 os
.execlp('man', 'man', *args
)
115 print >>sys
.stderr
, str(ex
)
118 interface_uri
= model
.canonical_iface_uri(interface_uri
)
125 sels
= helpers
.ensure_cached(interface_uri
, command
= command
)
131 selected_command
= sels
.commands
[0]
133 print >>sys
.stderr
, "No <command> in selections!"
134 selected_impl
= sels
.selections
[interface_uri
]
136 from zeroinstall
.injector
.iface_cache
import iface_cache
137 impl_path
= selected_impl
.local_path
or iface_cache
.stores
.lookup_any(selected_impl
.digests
)
140 main
= selected_command
.path
142 print >>sys
.stderr
, "No main program for interface '%s'" % interface_uri
145 prog_name
= os
.path
.basename(main
)
146 alias_name
= os
.path
.basename(args
[0])
150 # TODO: the feed should say where the man-pages are, but for now we'll accept
151 # a directory called man in some common locations...
152 for mandir
in ['man', 'share/man', 'usr/man', 'usr/share/man']:
153 manpath
= os
.path
.join(impl_path
, mandir
)
154 if os
.path
.isdir(manpath
):
155 # Note: unlike "man -M", this also copes with LANG settings...
156 os
.environ
['MANPATH'] = manpath
157 os
.execlp('man', 'man', prog_name
)
160 # No man directory given or found, so try searching for man files
163 for root
, dirs
, files
in os
.walk(impl_path
):
165 if f
.endswith('.gz'):
166 manpage_file
= f
[:-3]
169 if manpage_file
.endswith('.1') or \
170 manpage_file
.endswith('.6') or \
171 manpage_file
.endswith('.8'):
172 manpage_prog
= manpage_file
[:-2]
173 if manpage_prog
== prog_name
or manpage_prog
== alias_name
:
174 os
.execlp('man', 'man', os
.path
.join(root
, f
))
177 manpages
.append((root
, f
))
179 print "No matching manpage was found for '%s' (%s)" % (alias_name
, interface_uri
)
181 print "These non-matching man-pages were found, however:"
182 for root
, file in manpages
:
183 print os
.path
.join(root
, file)
186 if not os
.path
.isdir(first_path
):
187 print "(creating directory %s)" % first_path
188 os
.makedirs(first_path
)
191 os
.execlp('0launch', '0launch', '-gd', '--', interface_uri
)
195 interface
= model
.Interface(interface_uri
)
196 if not reader
.update_from_cache(interface
):
197 print >>sys
.stderr
, "Interface '%s' not currently in cache. Fetching..." % interface_uri
198 if os
.spawnlp(os
.P_WAIT
, '0launch', '0launch', '-d', interface_uri
):
199 raise model
.SafeException("0launch failed")
200 if not reader
.update_from_cache(interface
):
201 raise model
.SafeException("Interface still not in cache. Aborting.")
203 script
= os
.path
.join(first_path
, alias_prog
)
204 if os
.path
.exists(script
):
205 raise model
.SafeException("File '%s' already exists. Delete it first." % script
)
207 except model
.SafeException
as ex
:
208 print >>sys
.stderr
, ex
211 wrapper
= file(script
, 'w')
212 alias
.write_script(wrapper
, interface_uri
, main
, command
= command
)
214 # Make new script executable
215 os
.chmod(script
, 0o111 | os
.fstat(wrapper
.fileno()).st_mode
)
218 #print "Created script '%s'." % script
219 #print "To edit policy: 0alias %s" % alias_prog
220 if options
.user_path
:
221 pass # Assume user knows what they're doing
223 print >>sys
.stderr
, 'Warning: %s is not in $PATH. Add it with:\n%s' % (first_path
, export('PATH', first_path
+ ':$PATH'))
225 shell
= os
.environ
.get('SHELL', '?')
226 if not (shell
.endswith('/zsh') or shell
.endswith('/bash')):
227 print "(note: some shells require you to type 'rehash' now)"