Ran idioms filter on code
[zeroinstall.git] / 0alias
blob376c7188b938981f2c12987037b96e5bcfb948c1
1 #!/usr/bin/env python
2 # Copyright (C) 2010, Thomas Leonard
3 # See the README file for details, or visit http://0install.net.
5 from __future__ import print_function
6 import locale
7 from logging import warn
8 try:
9 locale.setlocale(locale.LC_ALL, '')
10 except locale.Error:
11 warn('Error setting locale (eg. Invalid locale)')
13 import os, sys
15 ## PATH ##
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', '?')
26 if 'csh' in shell:
27 return "setenv %s %s" % (name, value)
28 return "export %s=%s" % (name, value)
30 def find_path(paths):
31 """Find the first writable path in : separated list."""
32 for path in paths:
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
37 else:
38 break
39 else:
40 return None
42 return 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
49 if not in_path:
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()
66 if options.version:
67 import zeroinstall
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.")
75 sys.exit(0)
77 if options.manpage:
78 if len(args) != 1:
79 os.execlp('man', 'man', *args)
80 sys.exit(1)
82 if len(args) < 1 or len(args) > 3:
83 parser.print_help()
84 sys.exit(1)
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:
89 parser.print_help()
90 sys.exit(1)
92 if options.user_path:
93 first_path = options.user_path
95 if interface_uri is None:
96 try:
97 if not os.path.isabs(alias_prog):
98 full_path = support.find_in_path(alias_prog)
99 if not full_path:
100 raise alias.NotAnAliasScript("Not found in $PATH: " + alias_prog)
101 else:
102 full_path = alias_prog
104 interface_uri, main = alias.parse_script(full_path)
105 except alias.NotAnAliasScript as ex:
106 if options.manpage:
107 os.execlp('man', 'man', *args)
108 print(str(ex), file=sys.stderr)
109 sys.exit(1)
111 interface_uri = model.canonical_iface_uri(interface_uri)
113 if options.resolve:
114 print(interface_uri)
115 sys.exit(0)
117 if options.manpage:
118 sels = helpers.ensure_cached(interface_uri)
119 if not sels:
120 # Cancelled by user
121 sys.exit(1)
123 if sels.commands:
124 selected_command = sels.commands[0]
125 else:
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)
132 if main is None:
133 main = selected_command.path
134 if main is None:
135 print("No main program for interface '%s'" % interface_uri, file=sys.stderr)
136 sys.exit(1)
138 prog_name = os.path.basename(main)
139 alias_name = os.path.basename(args[0])
141 assert impl_path
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)
151 sys.exit(1)
153 # No man directory given or found, so try searching for man files
155 manpages = []
156 for root, dirs, files in os.walk(impl_path):
157 for f in files:
158 if f.endswith('.gz'):
159 manpage_file = f[:-3]
160 else:
161 manpage_file = f
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))
168 sys.exit(1)
169 else:
170 manpages.append((root, f))
172 print("No matching manpage was found for '%s' (%s)" % (alias_name, interface_uri))
173 if manpages:
174 print("These non-matching man-pages were found, however:")
175 for root, file in manpages:
176 print(os.path.join(root, file))
177 sys.exit(1)
179 if not os.path.isdir(first_path):
180 print("(creating directory %s)" % first_path)
181 os.makedirs(first_path)
183 if len(args) == 1:
184 os.execlp('0launch', '0launch', '-gd', '--', interface_uri)
185 sys.exit(1)
187 try:
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)
199 sys.exit(1)
200 except model.SafeException as ex:
201 print(ex, file=sys.stderr)
202 sys.exit(1)
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)
209 wrapper.close()
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
215 elif not in_path:
216 print('Warning: %s is not in $PATH. Add it with:\n%s' % (first_path, export('PATH', first_path + ':$PATH')), file=sys.stderr)
217 else:
218 shell = os.environ.get('SHELL', '?')
219 if not shell.endswith('/zsh'):
220 print("(note: some shells require you to type 'rehash' now)")