2 # Copyright (C) 2010, Thomas Leonard
3 # See the README file for details, or visit http://0install.net.
5 from __future__
import print_function
9 from logging
import warn
11 locale
.setlocale(locale
.LC_ALL
, '')
13 warn('Error setting locale (eg. Invalid locale)')
19 from optparse
import OptionParser
21 from zeroinstall
.injector
import reader
, model
22 from zeroinstall
import support
, alias
, helpers
23 from zeroinstall
.support
import basedir
25 def export(name
, value
):
26 """Try to guess the command to set an environment variable."""
27 shell
= os
.environ
.get('SHELL', '?')
29 return "setenv %s %s" % (name
, value
)
30 return "export %s=%s" % (name
, value
)
33 """Find the first writable path in : separated list."""
35 if os
.path
.realpath(path
).startswith(basedir
.xdg_cache_home
):
36 pass # print "Skipping cache", first_path
37 elif not os
.access(path
, os
.W_OK
):
38 pass # print "No access", first_path
46 # Do this here so we can include it in the help message.
47 # But, don't abort if there isn't one because we might
48 # be doing something else (e.g. --manpage)
49 first_path
= find_path(os
.environ
['PATH'].split(':'))
50 in_path
= first_path
is not None
52 first_path
= os
.path
.expanduser('~/bin/')
54 parser
= OptionParser(usage
="usage: %%prog [options] alias [interface [main]]\n\n"
55 "Creates a script to run 'interface' (will be created in\n"
56 "%s unless overridden by --dir).\n\n"
57 "If no interface is given, edits the policy for an existing alias.\n"
58 "For interfaces providing more than one executable, the desired\n"
59 "'main' binary or command may also be given." % first_path
)
60 parser
.add_option("-c", "--command", help="the command the alias will run (default 'run')", metavar
='COMMNAD')
61 parser
.add_option("-m", "--manpage", help="show the manual page for an existing alias", action
='store_true')
62 parser
.add_option("-r", "--resolve", help="show the URI for an alias", action
='store_true')
63 parser
.add_option("-v", "--verbose", help="more verbose output", action
='count')
64 parser
.add_option("-V", "--version", help="display version information", action
='store_true')
65 parser
.add_option("-d", "--dir", help="install in DIR", dest
="user_path", metavar
="DIR")
67 (options
, args
) = parser
.parse_args()
70 logger
= logging
.getLogger()
71 if options
.verbose
== 1:
72 logger
.setLevel(logging
.INFO
)
74 logger
.setLevel(logging
.DEBUG
)
75 hdlr
= logging
.StreamHandler()
76 fmt
= logging
.Formatter("%(levelname)s:%(message)s")
77 hdlr
.setFormatter(fmt
)
78 logger
.addHandler(hdlr
)
82 print("0alias (zero-install) " + zeroinstall
.version
)
83 print("Copyright (C) 2010 Thomas Leonard")
84 print("This program comes with ABSOLUTELY NO WARRANTY,")
85 print("to the extent permitted by law.")
86 print("You may redistribute copies of this program")
87 print("under the terms of the GNU Lesser General Public License.")
88 print("For more information about these matters, see the file named COPYING.")
93 os
.execlp('man', 'man', *args
)
96 if len(args
) < 1 or len(args
) > 3:
99 alias_prog
, interface_uri
, main
= (list(args
) + [None, None])[:3]
100 command
= options
.command
102 if options
.resolve
or options
.manpage
:
103 if interface_uri
is not None:
107 if options
.user_path
:
108 first_path
= options
.user_path
110 if interface_uri
is None:
112 print("Can't use --command when editing an existing alias", file=sys
.stderr
)
115 if not os
.path
.isabs(alias_prog
):
116 full_path
= support
.find_in_path(alias_prog
)
118 raise alias
.NotAnAliasScript("Not found in $PATH: " + alias_prog
)
120 full_path
= alias_prog
122 alias_info
= alias
.parse_script(full_path
)
123 interface_uri
= alias_info
.uri
124 main
= alias_info
.main
125 command
= alias_info
.command
126 except (alias
.NotAnAliasScript
, IOError) as ex
:
127 # (we get IOError if e.g. the script isn't readable)
129 logging
.debug("not a 0alias script '%s': %s", alias_prog
, ex
)
130 os
.execlp('man', 'man', *args
)
131 print(str(ex
), file=sys
.stderr
)
134 interface_uri
= model
.canonical_iface_uri(interface_uri
)
141 sels
= helpers
.ensure_cached(interface_uri
, command
= command
or 'run')
147 selected_command
= sels
.commands
[0]
149 print("No <command> in selections!", file=sys
.stderr
)
150 selected_impl
= sels
.selections
[interface_uri
]
152 from zeroinstall
.injector
.iface_cache
import iface_cache
153 impl_path
= selected_impl
.local_path
or iface_cache
.stores
.lookup_any(selected_impl
.digests
)
156 main
= selected_command
.path
158 print("No main program for interface '%s'" % interface_uri
, file=sys
.stderr
)
161 prog_name
= os
.path
.basename(main
)
162 alias_name
= os
.path
.basename(args
[0])
166 # TODO: the feed should say where the man-pages are, but for now we'll accept
167 # a directory called man in some common locations...
168 for mandir
in ['man', 'share/man', 'usr/man', 'usr/share/man']:
169 manpath
= os
.path
.join(impl_path
, mandir
)
170 if os
.path
.isdir(manpath
):
171 # Note: unlike "man -M", this also copes with LANG settings...
172 os
.environ
['MANPATH'] = manpath
173 os
.execlp('man', 'man', prog_name
)
176 # No man directory given or found, so try searching for man files
179 for root
, dirs
, files
in os
.walk(impl_path
):
181 if f
.endswith('.gz'):
182 manpage_file
= f
[:-3]
185 if manpage_file
.endswith('.1') or \
186 manpage_file
.endswith('.6') or \
187 manpage_file
.endswith('.8'):
188 manpage_prog
= manpage_file
[:-2]
189 if manpage_prog
== prog_name
or manpage_prog
== alias_name
:
190 os
.execlp('man', 'man', os
.path
.join(root
, f
))
193 manpages
.append((root
, f
))
195 print("No matching manpage was found for '%s' (%s)" % (alias_name
, interface_uri
))
197 print("These non-matching man-pages were found, however:")
198 for root
, file in manpages
:
199 print(os
.path
.join(root
, file))
202 if not os
.path
.isdir(first_path
):
203 print("(creating directory %s)" % first_path
)
204 os
.makedirs(first_path
)
207 os
.execlp('0launch', '0launch', '-gd', '--', interface_uri
)
211 interface
= model
.Interface(interface_uri
)
212 if not reader
.update_from_cache(interface
):
213 print("Interface '%s' not currently in cache. Fetching..." % interface_uri
, file=sys
.stderr
)
214 if os
.spawnlp(os
.P_WAIT
, '0launch', '0launch', '-d', interface_uri
):
215 raise model
.SafeException("0launch failed")
216 if not reader
.update_from_cache(interface
):
217 raise model
.SafeException("Interface still not in cache. Aborting.")
219 script
= os
.path
.join(first_path
, alias_prog
)
220 if os
.path
.exists(script
):
221 raise model
.SafeException("File '%s' already exists. Delete it first." % script
)
223 except model
.SafeException
as ex
:
224 print(ex
, file=sys
.stderr
)
227 wrapper
= open(script
, 'w')
228 alias
.write_script(wrapper
, interface_uri
, main
, command
= command
)
230 # Make new script executable
231 os
.chmod(script
, 0o111 | os
.fstat(wrapper
.fileno()).st_mode
)
234 #print "Created script '%s'." % script
235 #print "To edit policy: 0alias %s" % alias_prog
236 if options
.user_path
:
237 pass # Assume user knows what they're doing
239 print('Warning: %s is not in $PATH. Add it with:\n%s' % (first_path
, export('PATH', first_path
+ ':$PATH')), file=sys
.stderr
)
241 shell
= os
.environ
.get('SHELL', '?')
242 if not (shell
.endswith('/zsh') or shell
.endswith('/bash')):
243 print("(note: some shells require you to type 'rehash' now)")