2 # Copyright (C) 2010, Thomas Leonard
3 # See the README file for details, or visit http://0install.net.
5 from __future__
import print_function
7 from logging
import warn
9 locale
.setlocale(locale
.LC_ALL
, '')
11 warn('Error setting locale (eg. Invalid locale)')
17 from optparse
import OptionParser
19 from zeroinstall
.injector
import reader
, model
20 from zeroinstall
import support
, alias
, helpers
21 from zeroinstall
.support
import basedir
23 def export(name
, value
):
24 """Try to guess the command to set an environment variable."""
25 shell
= os
.environ
.get('SHELL', '?')
27 return "setenv %s %s" % (name
, value
)
28 return "export %s=%s" % (name
, value
)
31 """Find the first writable path in : separated list."""
33 if os
.path
.realpath(path
).startswith(basedir
.xdg_cache_home
):
34 pass # print "Skipping cache", first_path
35 elif not os
.access(path
, os
.W_OK
):
36 pass # print "No access", first_path
44 # Do this here so we can include it in the help message.
45 # But, don't abort if there isn't one because we might
46 # be doing something else (e.g. --manpage)
47 first_path
= find_path(os
.environ
['PATH'].split(':'))
48 in_path
= first_path
is not None
50 first_path
= os
.path
.expanduser('~/bin/')
52 parser
= OptionParser(usage
="usage: %%prog [options] alias [interface [main]]\n\n"
53 "Creates a script to run 'interface' (will be created in\n"
54 "%s unless overridden by --dir).\n"
55 "If no interface is given, edits the policy for an existing alias.\n"
56 "For interfaces providing more than one executable, the desired\n"
57 "'main' binary may also be given." % first_path
)
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]
87 if options
.resolve
or options
.manpage
:
88 if interface_uri
is not None:
93 first_path
= options
.user_path
95 if interface_uri
is None:
97 if not os
.path
.isabs(alias_prog
):
98 full_path
= support
.find_in_path(alias_prog
)
100 raise alias
.NotAnAliasScript("Not found in $PATH: " + alias_prog
)
102 full_path
= alias_prog
104 interface_uri
, main
= alias
.parse_script(full_path
)
105 except alias
.NotAnAliasScript
as ex
:
107 os
.execlp('man', 'man', *args
)
108 print(str(ex
), file=sys
.stderr
)
111 interface_uri
= model
.canonical_iface_uri(interface_uri
)
118 sels
= helpers
.ensure_cached(interface_uri
)
124 selected_command
= sels
.commands
[0]
126 print("No <command> in selections!", file=sys
.stderr
)
127 selected_impl
= sels
.selections
[interface_uri
]
129 from zeroinstall
.injector
.iface_cache
import iface_cache
130 impl_path
= selected_impl
.local_path
or iface_cache
.stores
.lookup_any(selected_impl
.digests
)
133 main
= selected_command
.path
135 print("No main program for interface '%s'" % interface_uri
, file=sys
.stderr
)
138 prog_name
= os
.path
.basename(main
)
139 alias_name
= os
.path
.basename(args
[0])
143 # TODO: the feed should say where the man-pages are, but for now we'll accept
144 # a directory called man in some common locations...
145 for mandir
in ['man', 'share/man', 'usr/man', 'usr/share/man']:
146 manpath
= os
.path
.join(impl_path
, mandir
)
147 if os
.path
.isdir(manpath
):
148 # Note: unlike "man -M", this also copes with LANG settings...
149 os
.environ
['MANPATH'] = manpath
150 os
.execlp('man', 'man', prog_name
)
153 # No man directory given or found, so try searching for man files
156 for root
, dirs
, files
in os
.walk(impl_path
):
158 if f
.endswith('.gz'):
159 manpage_file
= f
[:-3]
162 if manpage_file
.endswith('.1') or \
163 manpage_file
.endswith('.6') or \
164 manpage_file
.endswith('.8'):
165 manpage_prog
= manpage_file
[:-2]
166 if manpage_prog
== prog_name
or manpage_prog
== alias_name
:
167 os
.execlp('man', 'man', os
.path
.join(root
, f
))
170 manpages
.append((root
, f
))
172 print("No matching manpage was found for '%s' (%s)" % (alias_name
, interface_uri
))
174 print("These non-matching man-pages were found, however:")
175 for root
, file in manpages
:
176 print(os
.path
.join(root
, file))
179 if not os
.path
.isdir(first_path
):
180 print("(creating directory %s)" % first_path
)
181 os
.makedirs(first_path
)
184 os
.execlp('0launch', '0launch', '-gd', '--', interface_uri
)
188 interface
= model
.Interface(interface_uri
)
189 if not reader
.update_from_cache(interface
):
190 print("Interface '%s' not currently in cache. Fetching..." % interface_uri
, file=sys
.stderr
)
191 if os
.spawnlp(os
.P_WAIT
, '0launch', '0launch', '-d', interface_uri
):
192 raise model
.SafeException("0launch failed")
193 if not reader
.update_from_cache(interface
):
194 raise model
.SafeException("Interface still not in cache. Aborting.")
196 script
= os
.path
.join(first_path
, alias_prog
)
197 if os
.path
.exists(script
):
198 raise model
.SafeException("File '%s' already exists. Delete it first." % script
)
200 except model
.SafeException
as ex
:
201 print(ex
, file=sys
.stderr
)
204 wrapper
= file(script
, 'w')
205 alias
.write_script(wrapper
, interface_uri
, main
)
207 # Make new script executable
208 os
.chmod(script
, 0o111 | os
.fstat(wrapper
.fileno()).st_mode
)
211 #print "Created script '%s'." % script
212 #print "To edit policy: 0alias %s" % alias_prog
213 if options
.user_path
:
214 pass # Assume user knows what they're doing
216 print('Warning: %s is not in $PATH. Add it with:\n%s' % (first_path
, export('PATH', first_path
+ ':$PATH')), file=sys
.stderr
)
218 shell
= os
.environ
.get('SHELL', '?')
219 if not shell
.endswith('/zsh'):
220 print("(note: some shells require you to type 'rehash' now)")