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"
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 may also be given." % first_path
)
57 parser
.add_option("-m", "--manpage", help="show the manual page for an existing alias", action
='store_true')
58 parser
.add_option("-r", "--resolve", help="show the URI for an alias", action
='store_true')
59 parser
.add_option("-V", "--version", help="display version information", action
='store_true')
60 parser
.add_option("-d", "--dir", help="install in DIR", dest
="user_path", metavar
="DIR")
61 parser
.disable_interspersed_args()
63 (options
, args
) = parser
.parse_args()
67 print "0alias (zero-install) " + zeroinstall
.version
68 print "Copyright (C) 2010 Thomas Leonard"
69 print "This program comes with ABSOLUTELY NO WARRANTY,"
70 print "to the extent permitted by law."
71 print "You may redistribute copies of this program"
72 print "under the terms of the GNU Lesser General Public License."
73 print "For more information about these matters, see the file named COPYING."
78 os
.execlp('man', 'man', *args
)
81 if len(args
) < 1 or len(args
) > 3:
84 alias_prog
, interface_uri
, main
= (list(args
) + [None, None])[:3]
86 if options
.resolve
or options
.manpage
:
87 if interface_uri
is not None:
92 first_path
= options
.user_path
94 if interface_uri
is None:
96 if not os
.path
.isabs(alias_prog
):
97 full_path
= support
.find_in_path(alias_prog
)
99 raise alias
.NotAnAliasScript("Not found in $PATH: " + alias_prog
)
101 full_path
= alias_prog
103 interface_uri
, main
= alias
.parse_script(full_path
)
104 except alias
.NotAnAliasScript
, ex
:
106 os
.execlp('man', 'man', *args
)
107 print >>sys
.stderr
, str(ex
)
110 interface_uri
= model
.canonical_iface_uri(interface_uri
)
117 sels
= helpers
.ensure_cached(interface_uri
)
122 selected_impl
= sels
.selections
[interface_uri
]
124 from zeroinstall
.injector
.iface_cache
import iface_cache
125 impl_path
= selected_impl
.local_path
or iface_cache
.stores
.lookup(selected_impl
.id)
128 main
= selected_impl
.main
130 print >>sys
.stderr
, "No main program for interface '%s'" % interface_uri
133 prog_name
= os
.path
.basename(main
)
134 alias_name
= os
.path
.basename(args
[0])
138 # TODO: the feed should say where the man-pages are, but for now we'll accept
139 # a directory called man in some common locations...
140 for mandir
in ['man', 'share/man', 'usr/man', 'usr/share/man']:
141 manpath
= os
.path
.join(impl_path
, mandir
)
142 if os
.path
.isdir(manpath
):
143 # Note: unlike "man -M", this also copes with LANG settings...
144 os
.environ
['MANPATH'] = manpath
145 os
.execlp('man', 'man', prog_name
)
148 # No man directory given or found, so try searching for man files
151 for root
, dirs
, files
in os
.walk(impl_path
):
153 if f
.endswith('.gz'):
154 manpage_file
= f
[:-3]
157 if manpage_file
.endswith('.1') or \
158 manpage_file
.endswith('.6') or \
159 manpage_file
.endswith('.8'):
160 manpage_prog
= manpage_file
[:-2]
161 if manpage_prog
== prog_name
or manpage_prog
== alias_name
:
162 os
.execlp('man', 'man', os
.path
.join(root
, f
))
165 manpages
.append((root
, f
))
167 print "No matching manpage was found for '%s' (%s)" % (alias_name
, interface_uri
)
169 print "These non-matching man-pages were found, however:"
170 for root
, file in manpages
:
171 print os
.path
.join(root
, file)
174 if not os
.path
.isdir(first_path
):
175 print "(creating directory %s)" % first_path
176 os
.makedirs(first_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 if options
.user_path
:
209 pass # Assume user knows what they're doing
211 print >>sys
.stderr
, 'Warning: %s is not in $PATH. Add it with:\n%s' % (first_path
, export('PATH', first_path
+ ':$PATH'))
213 shell
= os
.environ
.get('SHELL', '?')
214 if not shell
.endswith('/zsh'):
215 print "(note: some shells require you to type 'rehash' now)"