##// END OF EJS Templates
setup.py, make: avoid problems with outdated, existing hgext/__index__.py*...
Thomas Arendsen Hein -
r21229:54d7657d stable
parent child Browse files
Show More
@@ -1,137 +1,137
1 # If you want to change PREFIX, do not just edit it below. The changed
1 # If you want to change PREFIX, do not just edit it below. The changed
2 # value wont get passed on to recursive make calls. You should instead
2 # value wont get passed on to recursive make calls. You should instead
3 # override the variable on the command like:
3 # override the variable on the command like:
4 #
4 #
5 # % make PREFIX=/opt/ install
5 # % make PREFIX=/opt/ install
6
6
7 PREFIX=/usr/local
7 PREFIX=/usr/local
8 export PREFIX
8 export PREFIX
9 PYTHON=python
9 PYTHON=python
10 PURE=
10 PURE=
11 PYFILES:=$(shell find mercurial hgext doc -name '*.py')
11 PYFILES:=$(shell find mercurial hgext doc -name '*.py')
12 DOCFILES=mercurial/help/*.txt
12 DOCFILES=mercurial/help/*.txt
13 export LANGUAGE=C
13 export LANGUAGE=C
14 export LC_ALL=C
14 export LC_ALL=C
15
15
16 # Set this to e.g. "mingw32" to use a non-default compiler.
16 # Set this to e.g. "mingw32" to use a non-default compiler.
17 COMPILER=
17 COMPILER=
18
18
19 help:
19 help:
20 @echo 'Commonly used make targets:'
20 @echo 'Commonly used make targets:'
21 @echo ' all - build program and documentation'
21 @echo ' all - build program and documentation'
22 @echo ' install - install program and man pages to $$PREFIX ($(PREFIX))'
22 @echo ' install - install program and man pages to $$PREFIX ($(PREFIX))'
23 @echo ' install-home - install with setup.py install --home=$$HOME ($(HOME))'
23 @echo ' install-home - install with setup.py install --home=$$HOME ($(HOME))'
24 @echo ' local - build for inplace usage'
24 @echo ' local - build for inplace usage'
25 @echo ' tests - run all tests in the automatic test suite'
25 @echo ' tests - run all tests in the automatic test suite'
26 @echo ' test-foo - run only specified tests (e.g. test-merge1.t)'
26 @echo ' test-foo - run only specified tests (e.g. test-merge1.t)'
27 @echo ' dist - run all tests and create a source tarball in dist/'
27 @echo ' dist - run all tests and create a source tarball in dist/'
28 @echo ' clean - remove files created by other targets'
28 @echo ' clean - remove files created by other targets'
29 @echo ' (except installed files or dist source tarball)'
29 @echo ' (except installed files or dist source tarball)'
30 @echo ' update-pot - update i18n/hg.pot'
30 @echo ' update-pot - update i18n/hg.pot'
31 @echo
31 @echo
32 @echo 'Example for a system-wide installation under /usr/local:'
32 @echo 'Example for a system-wide installation under /usr/local:'
33 @echo ' make all && su -c "make install" && hg version'
33 @echo ' make all && su -c "make install" && hg version'
34 @echo
34 @echo
35 @echo 'Example for a local installation (usable in this directory):'
35 @echo 'Example for a local installation (usable in this directory):'
36 @echo ' make local && ./hg version'
36 @echo ' make local && ./hg version'
37
37
38 all: build doc
38 all: build doc
39
39
40 local:
40 local:
41 $(PYTHON) setup.py $(PURE) \
41 $(PYTHON) setup.py $(PURE) \
42 build_py -c -d . \
42 build_py -c -d . \
43 build_ext $(COMPILER:%=-c %) -i \
43 build_ext $(COMPILER:%=-c %) -i \
44 build_hgexe $(COMPILER:%=-c %) -i \
44 build_hgexe $(COMPILER:%=-c %) -i \
45 build_mo
45 build_mo
46 env HGRCPATH= $(PYTHON) hg version
46 env HGRCPATH= $(PYTHON) hg version
47
47
48 build:
48 build:
49 $(PYTHON) setup.py $(PURE) build $(COMPILER:%=-c %)
49 $(PYTHON) setup.py $(PURE) build $(COMPILER:%=-c %)
50
50
51 doc:
51 doc:
52 $(MAKE) -C doc
52 $(MAKE) -C doc
53
53
54 clean:
54 clean:
55 -$(PYTHON) setup.py clean --all # ignore errors from this command
55 -$(PYTHON) setup.py clean --all # ignore errors from this command
56 find contrib doc hgext i18n mercurial tests \
56 find contrib doc hgext i18n mercurial tests \
57 \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';'
57 \( -name '*.py[cdo]' -o -name '*.so' \) -exec rm -f '{}' ';'
58 rm -f $(addprefix mercurial/,$(notdir $(wildcard mercurial/pure/[a-z]*.py)))
58 rm -f $(addprefix mercurial/,$(notdir $(wildcard mercurial/pure/[a-z]*.py)))
59 rm -f MANIFEST MANIFEST.in mercurial/__version__.py tests/*.err
59 rm -f MANIFEST MANIFEST.in mercurial/__version__.py hgext/__index__.py tests/*.err
60 rm -rf build mercurial/locale
60 rm -rf build mercurial/locale
61 $(MAKE) -C doc clean
61 $(MAKE) -C doc clean
62
62
63 install: install-bin install-doc
63 install: install-bin install-doc
64
64
65 install-bin: build
65 install-bin: build
66 $(PYTHON) setup.py $(PURE) install --root="$(DESTDIR)/" --prefix="$(PREFIX)" --force
66 $(PYTHON) setup.py $(PURE) install --root="$(DESTDIR)/" --prefix="$(PREFIX)" --force
67
67
68 install-doc: doc
68 install-doc: doc
69 cd doc && $(MAKE) $(MFLAGS) install
69 cd doc && $(MAKE) $(MFLAGS) install
70
70
71 install-home: install-home-bin install-home-doc
71 install-home: install-home-bin install-home-doc
72
72
73 install-home-bin: build
73 install-home-bin: build
74 $(PYTHON) setup.py $(PURE) install --home="$(HOME)" --prefix="" --force
74 $(PYTHON) setup.py $(PURE) install --home="$(HOME)" --prefix="" --force
75
75
76 install-home-doc: doc
76 install-home-doc: doc
77 cd doc && $(MAKE) $(MFLAGS) PREFIX="$(HOME)" install
77 cd doc && $(MAKE) $(MFLAGS) PREFIX="$(HOME)" install
78
78
79 MANIFEST-doc:
79 MANIFEST-doc:
80 $(MAKE) -C doc MANIFEST
80 $(MAKE) -C doc MANIFEST
81
81
82 MANIFEST.in: MANIFEST-doc
82 MANIFEST.in: MANIFEST-doc
83 hg manifest | sed -e 's/^/include /' > MANIFEST.in
83 hg manifest | sed -e 's/^/include /' > MANIFEST.in
84 echo include mercurial/__version__.py >> MANIFEST.in
84 echo include mercurial/__version__.py >> MANIFEST.in
85 sed -e 's/^/include /' < doc/MANIFEST >> MANIFEST.in
85 sed -e 's/^/include /' < doc/MANIFEST >> MANIFEST.in
86
86
87 dist: tests dist-notests
87 dist: tests dist-notests
88
88
89 dist-notests: doc MANIFEST.in
89 dist-notests: doc MANIFEST.in
90 TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist
90 TAR_OPTIONS="--owner=root --group=root --mode=u+w,go-w,a+rX-s" $(PYTHON) setup.py -q sdist
91
91
92 check: tests
92 check: tests
93
93
94 tests:
94 tests:
95 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS)
95 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS)
96
96
97 test-%:
97 test-%:
98 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@
98 cd tests && $(PYTHON) run-tests.py $(TESTFLAGS) $@
99
99
100 check-code:
100 check-code:
101 hg manifest | xargs python contrib/check-code.py
101 hg manifest | xargs python contrib/check-code.py
102
102
103 update-pot: i18n/hg.pot
103 update-pot: i18n/hg.pot
104
104
105 i18n/hg.pot: $(PYFILES) $(DOCFILES) i18n/posplit i18n/hggettext
105 i18n/hg.pot: $(PYFILES) $(DOCFILES) i18n/posplit i18n/hggettext
106 $(PYTHON) i18n/hggettext mercurial/commands.py \
106 $(PYTHON) i18n/hggettext mercurial/commands.py \
107 hgext/*.py hgext/*/__init__.py \
107 hgext/*.py hgext/*/__init__.py \
108 mercurial/fileset.py mercurial/revset.py \
108 mercurial/fileset.py mercurial/revset.py \
109 mercurial/templatefilters.py mercurial/templatekw.py \
109 mercurial/templatefilters.py mercurial/templatekw.py \
110 mercurial/filemerge.py \
110 mercurial/filemerge.py \
111 $(DOCFILES) > i18n/hg.pot.tmp
111 $(DOCFILES) > i18n/hg.pot.tmp
112 # All strings marked for translation in Mercurial contain
112 # All strings marked for translation in Mercurial contain
113 # ASCII characters only. But some files contain string
113 # ASCII characters only. But some files contain string
114 # literals like this '\037\213'. xgettext thinks it has to
114 # literals like this '\037\213'. xgettext thinks it has to
115 # parse them even though they are not marked for translation.
115 # parse them even though they are not marked for translation.
116 # Extracting with an explicit encoding of ISO-8859-1 will make
116 # Extracting with an explicit encoding of ISO-8859-1 will make
117 # xgettext "parse" and ignore them.
117 # xgettext "parse" and ignore them.
118 echo $(PYFILES) | xargs \
118 echo $(PYFILES) | xargs \
119 xgettext --package-name "Mercurial" \
119 xgettext --package-name "Mercurial" \
120 --msgid-bugs-address "<mercurial-devel@selenic.com>" \
120 --msgid-bugs-address "<mercurial-devel@selenic.com>" \
121 --copyright-holder "Matt Mackall <mpm@selenic.com> and others" \
121 --copyright-holder "Matt Mackall <mpm@selenic.com> and others" \
122 --from-code ISO-8859-1 --join --sort-by-file --add-comments=i18n: \
122 --from-code ISO-8859-1 --join --sort-by-file --add-comments=i18n: \
123 -d hg -p i18n -o hg.pot.tmp
123 -d hg -p i18n -o hg.pot.tmp
124 $(PYTHON) i18n/posplit i18n/hg.pot.tmp
124 $(PYTHON) i18n/posplit i18n/hg.pot.tmp
125 # The target file is not created before the last step. So it never is in
125 # The target file is not created before the last step. So it never is in
126 # an intermediate state.
126 # an intermediate state.
127 mv -f i18n/hg.pot.tmp i18n/hg.pot
127 mv -f i18n/hg.pot.tmp i18n/hg.pot
128
128
129 %.po: i18n/hg.pot
129 %.po: i18n/hg.pot
130 # work on a temporary copy for never having a half completed target
130 # work on a temporary copy for never having a half completed target
131 cp $@ $@.tmp
131 cp $@ $@.tmp
132 msgmerge --no-location --update $@.tmp $^
132 msgmerge --no-location --update $@.tmp $^
133 mv -f $@.tmp $@
133 mv -f $@.tmp $@
134
134
135 .PHONY: help all local build doc clean install install-bin install-doc \
135 .PHONY: help all local build doc clean install install-bin install-doc \
136 install-home install-home-bin install-home-doc dist dist-notests tests \
136 install-home install-home-bin install-home-doc dist dist-notests tests \
137 update-pot
137 update-pot
@@ -1,369 +1,369
1 # extensions.py - extension handling for mercurial
1 # extensions.py - extension handling for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import imp, os
8 import imp, os
9 import util, cmdutil, error
9 import util, cmdutil, error
10 from i18n import _, gettext
10 from i18n import _, gettext
11
11
12 _extensions = {}
12 _extensions = {}
13 _order = []
13 _order = []
14 _ignore = ['hbisect', 'bookmarks', 'parentrevspec', 'interhg', 'inotify']
14 _ignore = ['hbisect', 'bookmarks', 'parentrevspec', 'interhg', 'inotify']
15
15
16 def extensions(ui=None):
16 def extensions(ui=None):
17 if ui:
17 if ui:
18 def enabled(name):
18 def enabled(name):
19 for format in ['%s', 'hgext.%s']:
19 for format in ['%s', 'hgext.%s']:
20 conf = ui.config('extensions', format % name)
20 conf = ui.config('extensions', format % name)
21 if conf is not None and not conf.startswith('!'):
21 if conf is not None and not conf.startswith('!'):
22 return True
22 return True
23 else:
23 else:
24 enabled = lambda name: True
24 enabled = lambda name: True
25 for name in _order:
25 for name in _order:
26 module = _extensions[name]
26 module = _extensions[name]
27 if module and enabled(name):
27 if module and enabled(name):
28 yield name, module
28 yield name, module
29
29
30 def find(name):
30 def find(name):
31 '''return module with given extension name'''
31 '''return module with given extension name'''
32 mod = None
32 mod = None
33 try:
33 try:
34 mod = _extensions[name]
34 mod = _extensions[name]
35 except KeyError:
35 except KeyError:
36 for k, v in _extensions.iteritems():
36 for k, v in _extensions.iteritems():
37 if k.endswith('.' + name) or k.endswith('/' + name):
37 if k.endswith('.' + name) or k.endswith('/' + name):
38 mod = v
38 mod = v
39 break
39 break
40 if not mod:
40 if not mod:
41 raise KeyError(name)
41 raise KeyError(name)
42 return mod
42 return mod
43
43
44 def loadpath(path, module_name):
44 def loadpath(path, module_name):
45 module_name = module_name.replace('.', '_')
45 module_name = module_name.replace('.', '_')
46 path = util.normpath(util.expandpath(path))
46 path = util.normpath(util.expandpath(path))
47 if os.path.isdir(path):
47 if os.path.isdir(path):
48 # module/__init__.py style
48 # module/__init__.py style
49 d, f = os.path.split(path)
49 d, f = os.path.split(path)
50 fd, fpath, desc = imp.find_module(f, [d])
50 fd, fpath, desc = imp.find_module(f, [d])
51 return imp.load_module(module_name, fd, fpath, desc)
51 return imp.load_module(module_name, fd, fpath, desc)
52 else:
52 else:
53 try:
53 try:
54 return imp.load_source(module_name, path)
54 return imp.load_source(module_name, path)
55 except IOError, exc:
55 except IOError, exc:
56 if not exc.filename:
56 if not exc.filename:
57 exc.filename = path # python does not fill this
57 exc.filename = path # python does not fill this
58 raise
58 raise
59
59
60 def load(ui, name, path):
60 def load(ui, name, path):
61 if name.startswith('hgext.') or name.startswith('hgext/'):
61 if name.startswith('hgext.') or name.startswith('hgext/'):
62 shortname = name[6:]
62 shortname = name[6:]
63 else:
63 else:
64 shortname = name
64 shortname = name
65 if shortname in _ignore:
65 if shortname in _ignore:
66 return None
66 return None
67 if shortname in _extensions:
67 if shortname in _extensions:
68 return _extensions[shortname]
68 return _extensions[shortname]
69 _extensions[shortname] = None
69 _extensions[shortname] = None
70 if path:
70 if path:
71 # the module will be loaded in sys.modules
71 # the module will be loaded in sys.modules
72 # choose an unique name so that it doesn't
72 # choose an unique name so that it doesn't
73 # conflicts with other modules
73 # conflicts with other modules
74 mod = loadpath(path, 'hgext.%s' % name)
74 mod = loadpath(path, 'hgext.%s' % name)
75 else:
75 else:
76 def importh(name):
76 def importh(name):
77 mod = __import__(name)
77 mod = __import__(name)
78 components = name.split('.')
78 components = name.split('.')
79 for comp in components[1:]:
79 for comp in components[1:]:
80 mod = getattr(mod, comp)
80 mod = getattr(mod, comp)
81 return mod
81 return mod
82 try:
82 try:
83 mod = importh("hgext.%s" % name)
83 mod = importh("hgext.%s" % name)
84 except ImportError, err:
84 except ImportError, err:
85 ui.debug('could not import hgext.%s (%s): trying %s\n'
85 ui.debug('could not import hgext.%s (%s): trying %s\n'
86 % (name, err, name))
86 % (name, err, name))
87 mod = importh(name)
87 mod = importh(name)
88 _extensions[shortname] = mod
88 _extensions[shortname] = mod
89 _order.append(shortname)
89 _order.append(shortname)
90 return mod
90 return mod
91
91
92 def loadall(ui):
92 def loadall(ui):
93 result = ui.configitems("extensions")
93 result = ui.configitems("extensions")
94 newindex = len(_order)
94 newindex = len(_order)
95 for (name, path) in result:
95 for (name, path) in result:
96 if path:
96 if path:
97 if path[0] == '!':
97 if path[0] == '!':
98 continue
98 continue
99 try:
99 try:
100 load(ui, name, path)
100 load(ui, name, path)
101 except KeyboardInterrupt:
101 except KeyboardInterrupt:
102 raise
102 raise
103 except Exception, inst:
103 except Exception, inst:
104 if path:
104 if path:
105 ui.warn(_("*** failed to import extension %s from %s: %s\n")
105 ui.warn(_("*** failed to import extension %s from %s: %s\n")
106 % (name, path, inst))
106 % (name, path, inst))
107 else:
107 else:
108 ui.warn(_("*** failed to import extension %s: %s\n")
108 ui.warn(_("*** failed to import extension %s: %s\n")
109 % (name, inst))
109 % (name, inst))
110 if ui.traceback():
110 if ui.traceback():
111 return 1
111 return 1
112
112
113 for name in _order[newindex:]:
113 for name in _order[newindex:]:
114 uisetup = getattr(_extensions[name], 'uisetup', None)
114 uisetup = getattr(_extensions[name], 'uisetup', None)
115 if uisetup:
115 if uisetup:
116 uisetup(ui)
116 uisetup(ui)
117
117
118 for name in _order[newindex:]:
118 for name in _order[newindex:]:
119 extsetup = getattr(_extensions[name], 'extsetup', None)
119 extsetup = getattr(_extensions[name], 'extsetup', None)
120 if extsetup:
120 if extsetup:
121 try:
121 try:
122 extsetup(ui)
122 extsetup(ui)
123 except TypeError:
123 except TypeError:
124 if extsetup.func_code.co_argcount != 0:
124 if extsetup.func_code.co_argcount != 0:
125 raise
125 raise
126 extsetup() # old extsetup with no ui argument
126 extsetup() # old extsetup with no ui argument
127
127
128 def wrapcommand(table, command, wrapper):
128 def wrapcommand(table, command, wrapper):
129 '''Wrap the command named `command' in table
129 '''Wrap the command named `command' in table
130
130
131 Replace command in the command table with wrapper. The wrapped command will
131 Replace command in the command table with wrapper. The wrapped command will
132 be inserted into the command table specified by the table argument.
132 be inserted into the command table specified by the table argument.
133
133
134 The wrapper will be called like
134 The wrapper will be called like
135
135
136 wrapper(orig, *args, **kwargs)
136 wrapper(orig, *args, **kwargs)
137
137
138 where orig is the original (wrapped) function, and *args, **kwargs
138 where orig is the original (wrapped) function, and *args, **kwargs
139 are the arguments passed to it.
139 are the arguments passed to it.
140 '''
140 '''
141 assert util.safehasattr(wrapper, '__call__')
141 assert util.safehasattr(wrapper, '__call__')
142 aliases, entry = cmdutil.findcmd(command, table)
142 aliases, entry = cmdutil.findcmd(command, table)
143 for alias, e in table.iteritems():
143 for alias, e in table.iteritems():
144 if e is entry:
144 if e is entry:
145 key = alias
145 key = alias
146 break
146 break
147
147
148 origfn = entry[0]
148 origfn = entry[0]
149 def wrap(*args, **kwargs):
149 def wrap(*args, **kwargs):
150 return util.checksignature(wrapper)(
150 return util.checksignature(wrapper)(
151 util.checksignature(origfn), *args, **kwargs)
151 util.checksignature(origfn), *args, **kwargs)
152
152
153 wrap.__doc__ = getattr(origfn, '__doc__')
153 wrap.__doc__ = getattr(origfn, '__doc__')
154 wrap.__module__ = getattr(origfn, '__module__')
154 wrap.__module__ = getattr(origfn, '__module__')
155
155
156 newentry = list(entry)
156 newentry = list(entry)
157 newentry[0] = wrap
157 newentry[0] = wrap
158 table[key] = tuple(newentry)
158 table[key] = tuple(newentry)
159 return entry
159 return entry
160
160
161 def wrapfunction(container, funcname, wrapper):
161 def wrapfunction(container, funcname, wrapper):
162 '''Wrap the function named funcname in container
162 '''Wrap the function named funcname in container
163
163
164 Replace the funcname member in the given container with the specified
164 Replace the funcname member in the given container with the specified
165 wrapper. The container is typically a module, class, or instance.
165 wrapper. The container is typically a module, class, or instance.
166
166
167 The wrapper will be called like
167 The wrapper will be called like
168
168
169 wrapper(orig, *args, **kwargs)
169 wrapper(orig, *args, **kwargs)
170
170
171 where orig is the original (wrapped) function, and *args, **kwargs
171 where orig is the original (wrapped) function, and *args, **kwargs
172 are the arguments passed to it.
172 are the arguments passed to it.
173
173
174 Wrapping methods of the repository object is not recommended since
174 Wrapping methods of the repository object is not recommended since
175 it conflicts with extensions that extend the repository by
175 it conflicts with extensions that extend the repository by
176 subclassing. All extensions that need to extend methods of
176 subclassing. All extensions that need to extend methods of
177 localrepository should use this subclassing trick: namely,
177 localrepository should use this subclassing trick: namely,
178 reposetup() should look like
178 reposetup() should look like
179
179
180 def reposetup(ui, repo):
180 def reposetup(ui, repo):
181 class myrepo(repo.__class__):
181 class myrepo(repo.__class__):
182 def whatever(self, *args, **kwargs):
182 def whatever(self, *args, **kwargs):
183 [...extension stuff...]
183 [...extension stuff...]
184 super(myrepo, self).whatever(*args, **kwargs)
184 super(myrepo, self).whatever(*args, **kwargs)
185 [...extension stuff...]
185 [...extension stuff...]
186
186
187 repo.__class__ = myrepo
187 repo.__class__ = myrepo
188
188
189 In general, combining wrapfunction() with subclassing does not
189 In general, combining wrapfunction() with subclassing does not
190 work. Since you cannot control what other extensions are loaded by
190 work. Since you cannot control what other extensions are loaded by
191 your end users, you should play nicely with others by using the
191 your end users, you should play nicely with others by using the
192 subclass trick.
192 subclass trick.
193 '''
193 '''
194 assert util.safehasattr(wrapper, '__call__')
194 assert util.safehasattr(wrapper, '__call__')
195 def wrap(*args, **kwargs):
195 def wrap(*args, **kwargs):
196 return wrapper(origfn, *args, **kwargs)
196 return wrapper(origfn, *args, **kwargs)
197
197
198 origfn = getattr(container, funcname)
198 origfn = getattr(container, funcname)
199 assert util.safehasattr(origfn, '__call__')
199 assert util.safehasattr(origfn, '__call__')
200 setattr(container, funcname, wrap)
200 setattr(container, funcname, wrap)
201 return origfn
201 return origfn
202
202
203 def _disabledpaths(strip_init=False):
203 def _disabledpaths(strip_init=False):
204 '''find paths of disabled extensions. returns a dict of {name: path}
204 '''find paths of disabled extensions. returns a dict of {name: path}
205 removes /__init__.py from packages if strip_init is True'''
205 removes /__init__.py from packages if strip_init is True'''
206 import hgext
206 import hgext
207 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
207 extpath = os.path.dirname(os.path.abspath(hgext.__file__))
208 try: # might not be a filesystem path
208 try: # might not be a filesystem path
209 files = os.listdir(extpath)
209 files = os.listdir(extpath)
210 except OSError:
210 except OSError:
211 return {}
211 return {}
212
212
213 exts = {}
213 exts = {}
214 for e in files:
214 for e in files:
215 if e.endswith('.py'):
215 if e.endswith('.py'):
216 name = e.rsplit('.', 1)[0]
216 name = e.rsplit('.', 1)[0]
217 path = os.path.join(extpath, e)
217 path = os.path.join(extpath, e)
218 else:
218 else:
219 name = e
219 name = e
220 path = os.path.join(extpath, e, '__init__.py')
220 path = os.path.join(extpath, e, '__init__.py')
221 if not os.path.exists(path):
221 if not os.path.exists(path):
222 continue
222 continue
223 if strip_init:
223 if strip_init:
224 path = os.path.dirname(path)
224 path = os.path.dirname(path)
225 if name in exts or name in _order or name == '__init__':
225 if name in exts or name in _order or name == '__init__':
226 continue
226 continue
227 exts[name] = path
227 exts[name] = path
228 return exts
228 return exts
229
229
230 def _moduledoc(file):
230 def _moduledoc(file):
231 '''return the top-level python documentation for the given file
231 '''return the top-level python documentation for the given file
232
232
233 Loosely inspired by pydoc.source_synopsis(), but rewritten to
233 Loosely inspired by pydoc.source_synopsis(), but rewritten to
234 handle triple quotes and to return the whole text instead of just
234 handle triple quotes and to return the whole text instead of just
235 the synopsis'''
235 the synopsis'''
236 result = []
236 result = []
237
237
238 line = file.readline()
238 line = file.readline()
239 while line[:1] == '#' or not line.strip():
239 while line[:1] == '#' or not line.strip():
240 line = file.readline()
240 line = file.readline()
241 if not line:
241 if not line:
242 break
242 break
243
243
244 start = line[:3]
244 start = line[:3]
245 if start == '"""' or start == "'''":
245 if start == '"""' or start == "'''":
246 line = line[3:]
246 line = line[3:]
247 while line:
247 while line:
248 if line.rstrip().endswith(start):
248 if line.rstrip().endswith(start):
249 line = line.split(start)[0]
249 line = line.split(start)[0]
250 if line:
250 if line:
251 result.append(line)
251 result.append(line)
252 break
252 break
253 elif not line:
253 elif not line:
254 return None # unmatched delimiter
254 return None # unmatched delimiter
255 result.append(line)
255 result.append(line)
256 line = file.readline()
256 line = file.readline()
257 else:
257 else:
258 return None
258 return None
259
259
260 return ''.join(result)
260 return ''.join(result)
261
261
262 def _disabledhelp(path):
262 def _disabledhelp(path):
263 '''retrieve help synopsis of a disabled extension (without importing)'''
263 '''retrieve help synopsis of a disabled extension (without importing)'''
264 try:
264 try:
265 file = open(path)
265 file = open(path)
266 except IOError:
266 except IOError:
267 return
267 return
268 else:
268 else:
269 doc = _moduledoc(file)
269 doc = _moduledoc(file)
270 file.close()
270 file.close()
271
271
272 if doc: # extracting localized synopsis
272 if doc: # extracting localized synopsis
273 return gettext(doc).splitlines()[0]
273 return gettext(doc).splitlines()[0]
274 else:
274 else:
275 return _('(no help text available)')
275 return _('(no help text available)')
276
276
277 def disabled():
277 def disabled():
278 '''find disabled extensions from hgext. returns a dict of {name: desc}'''
278 '''find disabled extensions from hgext. returns a dict of {name: desc}'''
279 try:
279 try:
280 from hgext import __index__
280 from hgext import __index__
281 return dict((name, gettext(desc))
281 return dict((name, gettext(desc))
282 for name, desc in __index__.docs.iteritems()
282 for name, desc in __index__.docs.iteritems()
283 if name not in _order)
283 if name not in _order)
284 except ImportError:
284 except (ImportError, AttributeError):
285 pass
285 pass
286
286
287 paths = _disabledpaths()
287 paths = _disabledpaths()
288 if not paths:
288 if not paths:
289 return {}
289 return {}
290
290
291 exts = {}
291 exts = {}
292 for name, path in paths.iteritems():
292 for name, path in paths.iteritems():
293 doc = _disabledhelp(path)
293 doc = _disabledhelp(path)
294 if doc:
294 if doc:
295 exts[name] = doc
295 exts[name] = doc
296
296
297 return exts
297 return exts
298
298
299 def disabledext(name):
299 def disabledext(name):
300 '''find a specific disabled extension from hgext. returns desc'''
300 '''find a specific disabled extension from hgext. returns desc'''
301 try:
301 try:
302 from hgext import __index__
302 from hgext import __index__
303 if name in _order: # enabled
303 if name in _order: # enabled
304 return
304 return
305 else:
305 else:
306 return gettext(__index__.docs.get(name))
306 return gettext(__index__.docs.get(name))
307 except ImportError:
307 except (ImportError, AttributeError):
308 pass
308 pass
309
309
310 paths = _disabledpaths()
310 paths = _disabledpaths()
311 if name in paths:
311 if name in paths:
312 return _disabledhelp(paths[name])
312 return _disabledhelp(paths[name])
313
313
314 def disabledcmd(ui, cmd, strict=False):
314 def disabledcmd(ui, cmd, strict=False):
315 '''import disabled extensions until cmd is found.
315 '''import disabled extensions until cmd is found.
316 returns (cmdname, extname, module)'''
316 returns (cmdname, extname, module)'''
317
317
318 paths = _disabledpaths(strip_init=True)
318 paths = _disabledpaths(strip_init=True)
319 if not paths:
319 if not paths:
320 raise error.UnknownCommand(cmd)
320 raise error.UnknownCommand(cmd)
321
321
322 def findcmd(cmd, name, path):
322 def findcmd(cmd, name, path):
323 try:
323 try:
324 mod = loadpath(path, 'hgext.%s' % name)
324 mod = loadpath(path, 'hgext.%s' % name)
325 except Exception:
325 except Exception:
326 return
326 return
327 try:
327 try:
328 aliases, entry = cmdutil.findcmd(cmd,
328 aliases, entry = cmdutil.findcmd(cmd,
329 getattr(mod, 'cmdtable', {}), strict)
329 getattr(mod, 'cmdtable', {}), strict)
330 except (error.AmbiguousCommand, error.UnknownCommand):
330 except (error.AmbiguousCommand, error.UnknownCommand):
331 return
331 return
332 except Exception:
332 except Exception:
333 ui.warn(_('warning: error finding commands in %s\n') % path)
333 ui.warn(_('warning: error finding commands in %s\n') % path)
334 ui.traceback()
334 ui.traceback()
335 return
335 return
336 for c in aliases:
336 for c in aliases:
337 if c.startswith(cmd):
337 if c.startswith(cmd):
338 cmd = c
338 cmd = c
339 break
339 break
340 else:
340 else:
341 cmd = aliases[0]
341 cmd = aliases[0]
342 return (cmd, name, mod)
342 return (cmd, name, mod)
343
343
344 ext = None
344 ext = None
345 # first, search for an extension with the same name as the command
345 # first, search for an extension with the same name as the command
346 path = paths.pop(cmd, None)
346 path = paths.pop(cmd, None)
347 if path:
347 if path:
348 ext = findcmd(cmd, cmd, path)
348 ext = findcmd(cmd, cmd, path)
349 if not ext:
349 if not ext:
350 # otherwise, interrogate each extension until there's a match
350 # otherwise, interrogate each extension until there's a match
351 for name, path in paths.iteritems():
351 for name, path in paths.iteritems():
352 ext = findcmd(cmd, name, path)
352 ext = findcmd(cmd, name, path)
353 if ext:
353 if ext:
354 break
354 break
355 if ext and 'DEPRECATED' not in ext.__doc__:
355 if ext and 'DEPRECATED' not in ext.__doc__:
356 return ext
356 return ext
357
357
358 raise error.UnknownCommand(cmd)
358 raise error.UnknownCommand(cmd)
359
359
360 def enabled(shortname=True):
360 def enabled(shortname=True):
361 '''return a dict of {name: desc} of extensions'''
361 '''return a dict of {name: desc} of extensions'''
362 exts = {}
362 exts = {}
363 for ename, ext in extensions():
363 for ename, ext in extensions():
364 doc = (gettext(ext.__doc__) or _('(no help text available)'))
364 doc = (gettext(ext.__doc__) or _('(no help text available)'))
365 if shortname:
365 if shortname:
366 ename = ename.split('.')[-1]
366 ename = ename.split('.')[-1]
367 exts[ename] = doc.splitlines()[0].strip()
367 exts[ename] = doc.splitlines()[0].strip()
368
368
369 return exts
369 return exts
@@ -1,586 +1,588
1 #
1 #
2 # This is the mercurial setup script.
2 # This is the mercurial setup script.
3 #
3 #
4 # 'python setup.py install', or
4 # 'python setup.py install', or
5 # 'python setup.py --help' for more options
5 # 'python setup.py --help' for more options
6
6
7 import sys, platform
7 import sys, platform
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
8 if getattr(sys, 'version_info', (0, 0, 0)) < (2, 4, 0, 'final'):
9 raise SystemExit("Mercurial requires Python 2.4 or later.")
9 raise SystemExit("Mercurial requires Python 2.4 or later.")
10
10
11 if sys.version_info[0] >= 3:
11 if sys.version_info[0] >= 3:
12 def b(s):
12 def b(s):
13 '''A helper function to emulate 2.6+ bytes literals using string
13 '''A helper function to emulate 2.6+ bytes literals using string
14 literals.'''
14 literals.'''
15 return s.encode('latin1')
15 return s.encode('latin1')
16 printf = eval('print')
16 printf = eval('print')
17 libdir_escape = 'unicode_escape'
17 libdir_escape = 'unicode_escape'
18 else:
18 else:
19 libdir_escape = 'string_escape'
19 libdir_escape = 'string_escape'
20 def b(s):
20 def b(s):
21 '''A helper function to emulate 2.6+ bytes literals using string
21 '''A helper function to emulate 2.6+ bytes literals using string
22 literals.'''
22 literals.'''
23 return s
23 return s
24 def printf(*args, **kwargs):
24 def printf(*args, **kwargs):
25 f = kwargs.get('file', sys.stdout)
25 f = kwargs.get('file', sys.stdout)
26 end = kwargs.get('end', '\n')
26 end = kwargs.get('end', '\n')
27 f.write(b(' ').join(args) + end)
27 f.write(b(' ').join(args) + end)
28
28
29 # Solaris Python packaging brain damage
29 # Solaris Python packaging brain damage
30 try:
30 try:
31 import hashlib
31 import hashlib
32 sha = hashlib.sha1()
32 sha = hashlib.sha1()
33 except ImportError:
33 except ImportError:
34 try:
34 try:
35 import sha
35 import sha
36 except ImportError:
36 except ImportError:
37 raise SystemExit(
37 raise SystemExit(
38 "Couldn't import standard hashlib (incomplete Python install).")
38 "Couldn't import standard hashlib (incomplete Python install).")
39
39
40 try:
40 try:
41 import zlib
41 import zlib
42 except ImportError:
42 except ImportError:
43 raise SystemExit(
43 raise SystemExit(
44 "Couldn't import standard zlib (incomplete Python install).")
44 "Couldn't import standard zlib (incomplete Python install).")
45
45
46 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
46 # The base IronPython distribution (as of 2.7.1) doesn't support bz2
47 isironpython = False
47 isironpython = False
48 try:
48 try:
49 isironpython = (platform.python_implementation()
49 isironpython = (platform.python_implementation()
50 .lower().find("ironpython") != -1)
50 .lower().find("ironpython") != -1)
51 except AttributeError:
51 except AttributeError:
52 pass
52 pass
53
53
54 if isironpython:
54 if isironpython:
55 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
55 sys.stderr.write("warning: IronPython detected (no bz2 support)\n")
56 else:
56 else:
57 try:
57 try:
58 import bz2
58 import bz2
59 except ImportError:
59 except ImportError:
60 raise SystemExit(
60 raise SystemExit(
61 "Couldn't import standard bz2 (incomplete Python install).")
61 "Couldn't import standard bz2 (incomplete Python install).")
62
62
63 import os, subprocess, time
63 import os, subprocess, time
64 import re
64 import re
65 import shutil
65 import shutil
66 import tempfile
66 import tempfile
67 from distutils import log
67 from distutils import log
68 from distutils.core import setup, Command, Extension
68 from distutils.core import setup, Command, Extension
69 from distutils.dist import Distribution
69 from distutils.dist import Distribution
70 from distutils.command.build import build
70 from distutils.command.build import build
71 from distutils.command.build_ext import build_ext
71 from distutils.command.build_ext import build_ext
72 from distutils.command.build_py import build_py
72 from distutils.command.build_py import build_py
73 from distutils.command.install_scripts import install_scripts
73 from distutils.command.install_scripts import install_scripts
74 from distutils.spawn import spawn, find_executable
74 from distutils.spawn import spawn, find_executable
75 from distutils import cygwinccompiler
75 from distutils import cygwinccompiler
76 from distutils.errors import CCompilerError, DistutilsExecError
76 from distutils.errors import CCompilerError, DistutilsExecError
77 from distutils.sysconfig import get_python_inc, get_config_var
77 from distutils.sysconfig import get_python_inc, get_config_var
78 from distutils.version import StrictVersion
78 from distutils.version import StrictVersion
79
79
80 convert2to3 = '--c2to3' in sys.argv
80 convert2to3 = '--c2to3' in sys.argv
81 if convert2to3:
81 if convert2to3:
82 try:
82 try:
83 from distutils.command.build_py import build_py_2to3 as build_py
83 from distutils.command.build_py import build_py_2to3 as build_py
84 from lib2to3.refactor import get_fixers_from_package as getfixers
84 from lib2to3.refactor import get_fixers_from_package as getfixers
85 except ImportError:
85 except ImportError:
86 if sys.version_info[0] < 3:
86 if sys.version_info[0] < 3:
87 raise SystemExit("--c2to3 is only compatible with python3.")
87 raise SystemExit("--c2to3 is only compatible with python3.")
88 raise
88 raise
89 sys.path.append('contrib')
89 sys.path.append('contrib')
90 elif sys.version_info[0] >= 3:
90 elif sys.version_info[0] >= 3:
91 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
91 raise SystemExit("setup.py with python3 needs --c2to3 (experimental)")
92
92
93 scripts = ['hg']
93 scripts = ['hg']
94 if os.name == 'nt':
94 if os.name == 'nt':
95 scripts.append('contrib/win32/hg.bat')
95 scripts.append('contrib/win32/hg.bat')
96
96
97 # simplified version of distutils.ccompiler.CCompiler.has_function
97 # simplified version of distutils.ccompiler.CCompiler.has_function
98 # that actually removes its temporary files.
98 # that actually removes its temporary files.
99 def hasfunction(cc, funcname):
99 def hasfunction(cc, funcname):
100 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
100 tmpdir = tempfile.mkdtemp(prefix='hg-install-')
101 devnull = oldstderr = None
101 devnull = oldstderr = None
102 try:
102 try:
103 try:
103 try:
104 fname = os.path.join(tmpdir, 'funcname.c')
104 fname = os.path.join(tmpdir, 'funcname.c')
105 f = open(fname, 'w')
105 f = open(fname, 'w')
106 f.write('int main(void) {\n')
106 f.write('int main(void) {\n')
107 f.write(' %s();\n' % funcname)
107 f.write(' %s();\n' % funcname)
108 f.write('}\n')
108 f.write('}\n')
109 f.close()
109 f.close()
110 # Redirect stderr to /dev/null to hide any error messages
110 # Redirect stderr to /dev/null to hide any error messages
111 # from the compiler.
111 # from the compiler.
112 # This will have to be changed if we ever have to check
112 # This will have to be changed if we ever have to check
113 # for a function on Windows.
113 # for a function on Windows.
114 devnull = open('/dev/null', 'w')
114 devnull = open('/dev/null', 'w')
115 oldstderr = os.dup(sys.stderr.fileno())
115 oldstderr = os.dup(sys.stderr.fileno())
116 os.dup2(devnull.fileno(), sys.stderr.fileno())
116 os.dup2(devnull.fileno(), sys.stderr.fileno())
117 objects = cc.compile([fname], output_dir=tmpdir)
117 objects = cc.compile([fname], output_dir=tmpdir)
118 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
118 cc.link_executable(objects, os.path.join(tmpdir, "a.out"))
119 except Exception:
119 except Exception:
120 return False
120 return False
121 return True
121 return True
122 finally:
122 finally:
123 if oldstderr is not None:
123 if oldstderr is not None:
124 os.dup2(oldstderr, sys.stderr.fileno())
124 os.dup2(oldstderr, sys.stderr.fileno())
125 if devnull is not None:
125 if devnull is not None:
126 devnull.close()
126 devnull.close()
127 shutil.rmtree(tmpdir)
127 shutil.rmtree(tmpdir)
128
128
129 # py2exe needs to be installed to work
129 # py2exe needs to be installed to work
130 try:
130 try:
131 import py2exe
131 import py2exe
132 py2exeloaded = True
132 py2exeloaded = True
133 # import py2exe's patched Distribution class
133 # import py2exe's patched Distribution class
134 from distutils.core import Distribution
134 from distutils.core import Distribution
135 except ImportError:
135 except ImportError:
136 py2exeloaded = False
136 py2exeloaded = False
137
137
138 def runcmd(cmd, env):
138 def runcmd(cmd, env):
139 if sys.platform == 'plan9':
139 if sys.platform == 'plan9':
140 # subprocess kludge to work around issues in half-baked Python
140 # subprocess kludge to work around issues in half-baked Python
141 # ports, notably bichued/python:
141 # ports, notably bichued/python:
142 _, out, err = os.popen3(cmd)
142 _, out, err = os.popen3(cmd)
143 return str(out), str(err)
143 return str(out), str(err)
144 else:
144 else:
145 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
145 p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
146 stderr=subprocess.PIPE, env=env)
146 stderr=subprocess.PIPE, env=env)
147 out, err = p.communicate()
147 out, err = p.communicate()
148 return out, err
148 return out, err
149
149
150 def runhg(cmd, env):
150 def runhg(cmd, env):
151 out, err = runcmd(cmd, env)
151 out, err = runcmd(cmd, env)
152 # If root is executing setup.py, but the repository is owned by
152 # If root is executing setup.py, but the repository is owned by
153 # another user (as in "sudo python setup.py install") we will get
153 # another user (as in "sudo python setup.py install") we will get
154 # trust warnings since the .hg/hgrc file is untrusted. That is
154 # trust warnings since the .hg/hgrc file is untrusted. That is
155 # fine, we don't want to load it anyway. Python may warn about
155 # fine, we don't want to load it anyway. Python may warn about
156 # a missing __init__.py in mercurial/locale, we also ignore that.
156 # a missing __init__.py in mercurial/locale, we also ignore that.
157 err = [e for e in err.splitlines()
157 err = [e for e in err.splitlines()
158 if not e.startswith(b('not trusting file')) \
158 if not e.startswith(b('not trusting file')) \
159 and not e.startswith(b('warning: Not importing')) \
159 and not e.startswith(b('warning: Not importing')) \
160 and not e.startswith(b('obsolete feature not enabled'))]
160 and not e.startswith(b('obsolete feature not enabled'))]
161 if err:
161 if err:
162 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
162 printf("stderr from '%s':" % (' '.join(cmd)), file=sys.stderr)
163 printf(b('\n').join([b(' ') + e for e in err]), file=sys.stderr)
163 printf(b('\n').join([b(' ') + e for e in err]), file=sys.stderr)
164 return ''
164 return ''
165 return out
165 return out
166
166
167 version = ''
167 version = ''
168
168
169 # Execute hg out of this directory with a custom environment which
169 # Execute hg out of this directory with a custom environment which
170 # includes the pure Python modules in mercurial/pure. We also take
170 # includes the pure Python modules in mercurial/pure. We also take
171 # care to not use any hgrc files and do no localization.
171 # care to not use any hgrc files and do no localization.
172 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
172 pypath = ['mercurial', os.path.join('mercurial', 'pure')]
173 env = {'PYTHONPATH': os.pathsep.join(pypath),
173 env = {'PYTHONPATH': os.pathsep.join(pypath),
174 'HGRCPATH': '',
174 'HGRCPATH': '',
175 'LANGUAGE': 'C'}
175 'LANGUAGE': 'C'}
176 if 'LD_LIBRARY_PATH' in os.environ:
176 if 'LD_LIBRARY_PATH' in os.environ:
177 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
177 env['LD_LIBRARY_PATH'] = os.environ['LD_LIBRARY_PATH']
178 if 'SystemRoot' in os.environ:
178 if 'SystemRoot' in os.environ:
179 # Copy SystemRoot into the custom environment for Python 2.6
179 # Copy SystemRoot into the custom environment for Python 2.6
180 # under Windows. Otherwise, the subprocess will fail with
180 # under Windows. Otherwise, the subprocess will fail with
181 # error 0xc0150004. See: http://bugs.python.org/issue3440
181 # error 0xc0150004. See: http://bugs.python.org/issue3440
182 env['SystemRoot'] = os.environ['SystemRoot']
182 env['SystemRoot'] = os.environ['SystemRoot']
183
183
184 if os.path.isdir('.hg'):
184 if os.path.isdir('.hg'):
185 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
185 cmd = [sys.executable, 'hg', 'log', '-r', '.', '--template', '{tags}\n']
186 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
186 numerictags = [t for t in runhg(cmd, env).split() if t[0].isdigit()]
187 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
187 hgid = runhg([sys.executable, 'hg', 'id', '-i'], env).strip()
188 if numerictags: # tag(s) found
188 if numerictags: # tag(s) found
189 version = numerictags[-1]
189 version = numerictags[-1]
190 if hgid.endswith('+'): # propagate the dirty status to the tag
190 if hgid.endswith('+'): # propagate the dirty status to the tag
191 version += '+'
191 version += '+'
192 else: # no tag found
192 else: # no tag found
193 cmd = [sys.executable, 'hg', 'parents', '--template',
193 cmd = [sys.executable, 'hg', 'parents', '--template',
194 '{latesttag}+{latesttagdistance}-']
194 '{latesttag}+{latesttagdistance}-']
195 version = runhg(cmd, env) + hgid
195 version = runhg(cmd, env) + hgid
196 if version.endswith('+'):
196 if version.endswith('+'):
197 version += time.strftime('%Y%m%d')
197 version += time.strftime('%Y%m%d')
198 elif os.path.exists('.hg_archival.txt'):
198 elif os.path.exists('.hg_archival.txt'):
199 kw = dict([[t.strip() for t in l.split(':', 1)]
199 kw = dict([[t.strip() for t in l.split(':', 1)]
200 for l in open('.hg_archival.txt')])
200 for l in open('.hg_archival.txt')])
201 if 'tag' in kw:
201 if 'tag' in kw:
202 version = kw['tag']
202 version = kw['tag']
203 elif 'latesttag' in kw:
203 elif 'latesttag' in kw:
204 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
204 version = '%(latesttag)s+%(latesttagdistance)s-%(node).12s' % kw
205 else:
205 else:
206 version = kw.get('node', '')[:12]
206 version = kw.get('node', '')[:12]
207
207
208 if version:
208 if version:
209 f = open("mercurial/__version__.py", "w")
209 f = open("mercurial/__version__.py", "w")
210 f.write('# this file is autogenerated by setup.py\n')
210 f.write('# this file is autogenerated by setup.py\n')
211 f.write('version = "%s"\n' % version)
211 f.write('version = "%s"\n' % version)
212 f.close()
212 f.close()
213
213
214
214
215 try:
215 try:
216 from mercurial import __version__
216 from mercurial import __version__
217 version = __version__.version
217 version = __version__.version
218 except ImportError:
218 except ImportError:
219 version = 'unknown'
219 version = 'unknown'
220
220
221 class hgbuild(build):
221 class hgbuild(build):
222 # Insert hgbuildmo first so that files in mercurial/locale/ are found
222 # Insert hgbuildmo first so that files in mercurial/locale/ are found
223 # when build_py is run next.
223 # when build_py is run next.
224 sub_commands = [('build_mo', None),
224 sub_commands = [('build_mo', None),
225
225
226 # We also need build_ext before build_py. Otherwise, when 2to3 is
226 # We also need build_ext before build_py. Otherwise, when 2to3 is
227 # called (in build_py), it will not find osutil & friends,
227 # called (in build_py), it will not find osutil & friends,
228 # thinking that those modules are global and, consequently, making
228 # thinking that those modules are global and, consequently, making
229 # a mess, now that all module imports are global.
229 # a mess, now that all module imports are global.
230
230
231 ('build_ext', build.has_ext_modules),
231 ('build_ext', build.has_ext_modules),
232 ] + build.sub_commands
232 ] + build.sub_commands
233
233
234 class hgbuildmo(build):
234 class hgbuildmo(build):
235
235
236 description = "build translations (.mo files)"
236 description = "build translations (.mo files)"
237
237
238 def run(self):
238 def run(self):
239 if not find_executable('msgfmt'):
239 if not find_executable('msgfmt'):
240 self.warn("could not find msgfmt executable, no translations "
240 self.warn("could not find msgfmt executable, no translations "
241 "will be built")
241 "will be built")
242 return
242 return
243
243
244 podir = 'i18n'
244 podir = 'i18n'
245 if not os.path.isdir(podir):
245 if not os.path.isdir(podir):
246 self.warn("could not find %s/ directory" % podir)
246 self.warn("could not find %s/ directory" % podir)
247 return
247 return
248
248
249 join = os.path.join
249 join = os.path.join
250 for po in os.listdir(podir):
250 for po in os.listdir(podir):
251 if not po.endswith('.po'):
251 if not po.endswith('.po'):
252 continue
252 continue
253 pofile = join(podir, po)
253 pofile = join(podir, po)
254 modir = join('locale', po[:-3], 'LC_MESSAGES')
254 modir = join('locale', po[:-3], 'LC_MESSAGES')
255 mofile = join(modir, 'hg.mo')
255 mofile = join(modir, 'hg.mo')
256 mobuildfile = join('mercurial', mofile)
256 mobuildfile = join('mercurial', mofile)
257 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
257 cmd = ['msgfmt', '-v', '-o', mobuildfile, pofile]
258 if sys.platform != 'sunos5':
258 if sys.platform != 'sunos5':
259 # msgfmt on Solaris does not know about -c
259 # msgfmt on Solaris does not know about -c
260 cmd.append('-c')
260 cmd.append('-c')
261 self.mkpath(join('mercurial', modir))
261 self.mkpath(join('mercurial', modir))
262 self.make_file([pofile], mobuildfile, spawn, (cmd,))
262 self.make_file([pofile], mobuildfile, spawn, (cmd,))
263
263
264
264
265 class hgdist(Distribution):
265 class hgdist(Distribution):
266 pure = 0
266 pure = 0
267
267
268 global_options = Distribution.global_options + \
268 global_options = Distribution.global_options + \
269 [('pure', None, "use pure (slow) Python "
269 [('pure', None, "use pure (slow) Python "
270 "code instead of C extensions"),
270 "code instead of C extensions"),
271 ('c2to3', None, "(experimental!) convert "
271 ('c2to3', None, "(experimental!) convert "
272 "code with 2to3"),
272 "code with 2to3"),
273 ]
273 ]
274
274
275 def has_ext_modules(self):
275 def has_ext_modules(self):
276 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
276 # self.ext_modules is emptied in hgbuildpy.finalize_options which is
277 # too late for some cases
277 # too late for some cases
278 return not self.pure and Distribution.has_ext_modules(self)
278 return not self.pure and Distribution.has_ext_modules(self)
279
279
280 class hgbuildext(build_ext):
280 class hgbuildext(build_ext):
281
281
282 def build_extension(self, ext):
282 def build_extension(self, ext):
283 try:
283 try:
284 build_ext.build_extension(self, ext)
284 build_ext.build_extension(self, ext)
285 except CCompilerError:
285 except CCompilerError:
286 if not getattr(ext, 'optional', False):
286 if not getattr(ext, 'optional', False):
287 raise
287 raise
288 log.warn("Failed to build optional extension '%s' (skipping)",
288 log.warn("Failed to build optional extension '%s' (skipping)",
289 ext.name)
289 ext.name)
290
290
291 class hgbuildpy(build_py):
291 class hgbuildpy(build_py):
292 if convert2to3:
292 if convert2to3:
293 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
293 fixer_names = sorted(set(getfixers("lib2to3.fixes") +
294 getfixers("hgfixes")))
294 getfixers("hgfixes")))
295
295
296 def finalize_options(self):
296 def finalize_options(self):
297 build_py.finalize_options(self)
297 build_py.finalize_options(self)
298
298
299 if self.distribution.pure:
299 if self.distribution.pure:
300 if self.py_modules is None:
300 if self.py_modules is None:
301 self.py_modules = []
301 self.py_modules = []
302 for ext in self.distribution.ext_modules:
302 for ext in self.distribution.ext_modules:
303 if ext.name.startswith("mercurial."):
303 if ext.name.startswith("mercurial."):
304 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
304 self.py_modules.append("mercurial.pure.%s" % ext.name[10:])
305 self.distribution.ext_modules = []
305 self.distribution.ext_modules = []
306 else:
306 else:
307 h = os.path.join(get_python_inc(), 'Python.h')
307 h = os.path.join(get_python_inc(), 'Python.h')
308 if not os.path.exists(h):
308 if not os.path.exists(h):
309 raise SystemExit('Python headers are required to build '
309 raise SystemExit('Python headers are required to build '
310 'Mercurial but weren\'t found in %s' % h)
310 'Mercurial but weren\'t found in %s' % h)
311
311
312 def find_modules(self):
312 def find_modules(self):
313 modules = build_py.find_modules(self)
313 modules = build_py.find_modules(self)
314 for module in modules:
314 for module in modules:
315 if module[0] == "mercurial.pure":
315 if module[0] == "mercurial.pure":
316 if module[1] != "__init__":
316 if module[1] != "__init__":
317 yield ("mercurial", module[1], module[2])
317 yield ("mercurial", module[1], module[2])
318 else:
318 else:
319 yield module
319 yield module
320
320
321 class buildhgextindex(Command):
321 class buildhgextindex(Command):
322 description = 'generate prebuilt index of hgext (for frozen package)'
322 description = 'generate prebuilt index of hgext (for frozen package)'
323 user_options = []
323 user_options = []
324 _indexfilename = 'hgext/__index__.py'
324 _indexfilename = 'hgext/__index__.py'
325
325
326 def initialize_options(self):
326 def initialize_options(self):
327 pass
327 pass
328
328
329 def finalize_options(self):
329 def finalize_options(self):
330 pass
330 pass
331
331
332 def run(self):
332 def run(self):
333 if os.path.exists(self._indexfilename):
333 if os.path.exists(self._indexfilename):
334 os.unlink(self._indexfilename)
334 f = open(self._indexfilename, 'w')
335 f.write('# empty\n')
336 f.close()
335
337
336 # here no extension enabled, disabled() lists up everything
338 # here no extension enabled, disabled() lists up everything
337 code = ('import pprint; from mercurial import extensions; '
339 code = ('import pprint; from mercurial import extensions; '
338 'pprint.pprint(extensions.disabled())')
340 'pprint.pprint(extensions.disabled())')
339 out, err = runcmd([sys.executable, '-c', code], env)
341 out, err = runcmd([sys.executable, '-c', code], env)
340 if err:
342 if err:
341 raise DistutilsExecError(err)
343 raise DistutilsExecError(err)
342
344
343 f = open(self._indexfilename, 'w')
345 f = open(self._indexfilename, 'w')
344 f.write('# this file is autogenerated by setup.py\n')
346 f.write('# this file is autogenerated by setup.py\n')
345 f.write('docs = ')
347 f.write('docs = ')
346 f.write(out)
348 f.write(out)
347 f.close()
349 f.close()
348
350
349 class buildhgexe(build_ext):
351 class buildhgexe(build_ext):
350 description = 'compile hg.exe from mercurial/exewrapper.c'
352 description = 'compile hg.exe from mercurial/exewrapper.c'
351
353
352 def build_extensions(self):
354 def build_extensions(self):
353 if os.name != 'nt':
355 if os.name != 'nt':
354 return
356 return
355 if isinstance(self.compiler, HackedMingw32CCompiler):
357 if isinstance(self.compiler, HackedMingw32CCompiler):
356 self.compiler.compiler_so = self.compiler.compiler # no -mdll
358 self.compiler.compiler_so = self.compiler.compiler # no -mdll
357 self.compiler.dll_libraries = [] # no -lmsrvc90
359 self.compiler.dll_libraries = [] # no -lmsrvc90
358 hv = sys.hexversion
360 hv = sys.hexversion
359 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
361 pythonlib = 'python%d%d' % (hv >> 24, (hv >> 16) & 0xff)
360 f = open('mercurial/hgpythonlib.h', 'wb')
362 f = open('mercurial/hgpythonlib.h', 'wb')
361 f.write('/* this file is autogenerated by setup.py */\n')
363 f.write('/* this file is autogenerated by setup.py */\n')
362 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
364 f.write('#define HGPYTHONLIB "%s"\n' % pythonlib)
363 f.close()
365 f.close()
364 objects = self.compiler.compile(['mercurial/exewrapper.c'],
366 objects = self.compiler.compile(['mercurial/exewrapper.c'],
365 output_dir=self.build_temp)
367 output_dir=self.build_temp)
366 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
368 dir = os.path.dirname(self.get_ext_fullpath('dummy'))
367 target = os.path.join(dir, 'hg')
369 target = os.path.join(dir, 'hg')
368 self.compiler.link_executable(objects, target,
370 self.compiler.link_executable(objects, target,
369 libraries=[],
371 libraries=[],
370 output_dir=self.build_temp)
372 output_dir=self.build_temp)
371
373
372 class hginstallscripts(install_scripts):
374 class hginstallscripts(install_scripts):
373 '''
375 '''
374 This is a specialization of install_scripts that replaces the @LIBDIR@ with
376 This is a specialization of install_scripts that replaces the @LIBDIR@ with
375 the configured directory for modules. If possible, the path is made relative
377 the configured directory for modules. If possible, the path is made relative
376 to the directory for scripts.
378 to the directory for scripts.
377 '''
379 '''
378
380
379 def initialize_options(self):
381 def initialize_options(self):
380 install_scripts.initialize_options(self)
382 install_scripts.initialize_options(self)
381
383
382 self.install_lib = None
384 self.install_lib = None
383
385
384 def finalize_options(self):
386 def finalize_options(self):
385 install_scripts.finalize_options(self)
387 install_scripts.finalize_options(self)
386 self.set_undefined_options('install',
388 self.set_undefined_options('install',
387 ('install_lib', 'install_lib'))
389 ('install_lib', 'install_lib'))
388
390
389 def run(self):
391 def run(self):
390 install_scripts.run(self)
392 install_scripts.run(self)
391
393
392 if (os.path.splitdrive(self.install_dir)[0] !=
394 if (os.path.splitdrive(self.install_dir)[0] !=
393 os.path.splitdrive(self.install_lib)[0]):
395 os.path.splitdrive(self.install_lib)[0]):
394 # can't make relative paths from one drive to another, so use an
396 # can't make relative paths from one drive to another, so use an
395 # absolute path instead
397 # absolute path instead
396 libdir = self.install_lib
398 libdir = self.install_lib
397 else:
399 else:
398 common = os.path.commonprefix((self.install_dir, self.install_lib))
400 common = os.path.commonprefix((self.install_dir, self.install_lib))
399 rest = self.install_dir[len(common):]
401 rest = self.install_dir[len(common):]
400 uplevel = len([n for n in os.path.split(rest) if n])
402 uplevel = len([n for n in os.path.split(rest) if n])
401
403
402 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
404 libdir = uplevel * ('..' + os.sep) + self.install_lib[len(common):]
403
405
404 for outfile in self.outfiles:
406 for outfile in self.outfiles:
405 fp = open(outfile, 'rb')
407 fp = open(outfile, 'rb')
406 data = fp.read()
408 data = fp.read()
407 fp.close()
409 fp.close()
408
410
409 # skip binary files
411 # skip binary files
410 if b('\0') in data:
412 if b('\0') in data:
411 continue
413 continue
412
414
413 data = data.replace(b('@LIBDIR@'), libdir.encode(libdir_escape))
415 data = data.replace(b('@LIBDIR@'), libdir.encode(libdir_escape))
414 fp = open(outfile, 'wb')
416 fp = open(outfile, 'wb')
415 fp.write(data)
417 fp.write(data)
416 fp.close()
418 fp.close()
417
419
418 cmdclass = {'build': hgbuild,
420 cmdclass = {'build': hgbuild,
419 'build_mo': hgbuildmo,
421 'build_mo': hgbuildmo,
420 'build_ext': hgbuildext,
422 'build_ext': hgbuildext,
421 'build_py': hgbuildpy,
423 'build_py': hgbuildpy,
422 'build_hgextindex': buildhgextindex,
424 'build_hgextindex': buildhgextindex,
423 'install_scripts': hginstallscripts,
425 'install_scripts': hginstallscripts,
424 'build_hgexe': buildhgexe,
426 'build_hgexe': buildhgexe,
425 }
427 }
426
428
427 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
429 packages = ['mercurial', 'mercurial.hgweb', 'mercurial.httpclient',
428 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
430 'hgext', 'hgext.convert', 'hgext.highlight', 'hgext.zeroconf',
429 'hgext.largefiles']
431 'hgext.largefiles']
430
432
431 pymodules = []
433 pymodules = []
432
434
433 common_depends = ['mercurial/util.h']
435 common_depends = ['mercurial/util.h']
434
436
435 extmodules = [
437 extmodules = [
436 Extension('mercurial.base85', ['mercurial/base85.c'],
438 Extension('mercurial.base85', ['mercurial/base85.c'],
437 depends=common_depends),
439 depends=common_depends),
438 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
440 Extension('mercurial.bdiff', ['mercurial/bdiff.c'],
439 depends=common_depends),
441 depends=common_depends),
440 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
442 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'],
441 depends=common_depends),
443 depends=common_depends),
442 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
444 Extension('mercurial.mpatch', ['mercurial/mpatch.c'],
443 depends=common_depends),
445 depends=common_depends),
444 Extension('mercurial.parsers', ['mercurial/dirs.c',
446 Extension('mercurial.parsers', ['mercurial/dirs.c',
445 'mercurial/parsers.c',
447 'mercurial/parsers.c',
446 'mercurial/pathencode.c'],
448 'mercurial/pathencode.c'],
447 depends=common_depends),
449 depends=common_depends),
448 ]
450 ]
449
451
450 osutil_ldflags = []
452 osutil_ldflags = []
451
453
452 if sys.platform == 'darwin':
454 if sys.platform == 'darwin':
453 osutil_ldflags += ['-framework', 'ApplicationServices']
455 osutil_ldflags += ['-framework', 'ApplicationServices']
454
456
455 # disable osutil.c under windows + python 2.4 (issue1364)
457 # disable osutil.c under windows + python 2.4 (issue1364)
456 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
458 if sys.platform == 'win32' and sys.version_info < (2, 5, 0, 'final'):
457 pymodules.append('mercurial.pure.osutil')
459 pymodules.append('mercurial.pure.osutil')
458 else:
460 else:
459 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
461 extmodules.append(Extension('mercurial.osutil', ['mercurial/osutil.c'],
460 extra_link_args=osutil_ldflags,
462 extra_link_args=osutil_ldflags,
461 depends=common_depends))
463 depends=common_depends))
462
464
463 # the -mno-cygwin option has been deprecated for years
465 # the -mno-cygwin option has been deprecated for years
464 Mingw32CCompiler = cygwinccompiler.Mingw32CCompiler
466 Mingw32CCompiler = cygwinccompiler.Mingw32CCompiler
465
467
466 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
468 class HackedMingw32CCompiler(cygwinccompiler.Mingw32CCompiler):
467 def __init__(self, *args, **kwargs):
469 def __init__(self, *args, **kwargs):
468 Mingw32CCompiler.__init__(self, *args, **kwargs)
470 Mingw32CCompiler.__init__(self, *args, **kwargs)
469 for i in 'compiler compiler_so linker_exe linker_so'.split():
471 for i in 'compiler compiler_so linker_exe linker_so'.split():
470 try:
472 try:
471 getattr(self, i).remove('-mno-cygwin')
473 getattr(self, i).remove('-mno-cygwin')
472 except ValueError:
474 except ValueError:
473 pass
475 pass
474
476
475 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
477 cygwinccompiler.Mingw32CCompiler = HackedMingw32CCompiler
476
478
477 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
479 packagedata = {'mercurial': ['locale/*/LC_MESSAGES/hg.mo',
478 'help/*.txt']}
480 'help/*.txt']}
479
481
480 def ordinarypath(p):
482 def ordinarypath(p):
481 return p and p[0] != '.' and p[-1] != '~'
483 return p and p[0] != '.' and p[-1] != '~'
482
484
483 for root in ('templates',):
485 for root in ('templates',):
484 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
486 for curdir, dirs, files in os.walk(os.path.join('mercurial', root)):
485 curdir = curdir.split(os.sep, 1)[1]
487 curdir = curdir.split(os.sep, 1)[1]
486 dirs[:] = filter(ordinarypath, dirs)
488 dirs[:] = filter(ordinarypath, dirs)
487 for f in filter(ordinarypath, files):
489 for f in filter(ordinarypath, files):
488 f = os.path.join(curdir, f)
490 f = os.path.join(curdir, f)
489 packagedata['mercurial'].append(f)
491 packagedata['mercurial'].append(f)
490
492
491 datafiles = []
493 datafiles = []
492 setupversion = version
494 setupversion = version
493 extra = {}
495 extra = {}
494
496
495 if py2exeloaded:
497 if py2exeloaded:
496 extra['console'] = [
498 extra['console'] = [
497 {'script':'hg',
499 {'script':'hg',
498 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
500 'copyright':'Copyright (C) 2005-2010 Matt Mackall and others',
499 'product_version':version}]
501 'product_version':version}]
500 # sub command of 'build' because 'py2exe' does not handle sub_commands
502 # sub command of 'build' because 'py2exe' does not handle sub_commands
501 build.sub_commands.insert(0, ('build_hgextindex', None))
503 build.sub_commands.insert(0, ('build_hgextindex', None))
502
504
503 if os.name == 'nt':
505 if os.name == 'nt':
504 # Windows binary file versions for exe/dll files must have the
506 # Windows binary file versions for exe/dll files must have the
505 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
507 # form W.X.Y.Z, where W,X,Y,Z are numbers in the range 0..65535
506 setupversion = version.split('+', 1)[0]
508 setupversion = version.split('+', 1)[0]
507
509
508 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
510 if sys.platform == 'darwin' and os.path.exists('/usr/bin/xcodebuild'):
509 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
511 version = runcmd(['/usr/bin/xcodebuild', '-version'], {})[0].splitlines()
510 if version:
512 if version:
511 version = version[0]
513 version = version[0]
512 xcode4 = (version.startswith('Xcode') and
514 xcode4 = (version.startswith('Xcode') and
513 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
515 StrictVersion(version.split()[1]) >= StrictVersion('4.0'))
514 xcode51 = re.match(r'^Xcode\s+5\.1\.', version) is not None
516 xcode51 = re.match(r'^Xcode\s+5\.1\.', version) is not None
515 else:
517 else:
516 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
518 # xcodebuild returns empty on OS X Lion with XCode 4.3 not
517 # installed, but instead with only command-line tools. Assume
519 # installed, but instead with only command-line tools. Assume
518 # that only happens on >= Lion, thus no PPC support.
520 # that only happens on >= Lion, thus no PPC support.
519 xcode4 = True
521 xcode4 = True
520 xcode51 = False
522 xcode51 = False
521
523
522 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
524 # XCode 4.0 dropped support for ppc architecture, which is hardcoded in
523 # distutils.sysconfig
525 # distutils.sysconfig
524 if xcode4:
526 if xcode4:
525 os.environ['ARCHFLAGS'] = ''
527 os.environ['ARCHFLAGS'] = ''
526
528
527 # XCode 5.1 changes clang such that it now fails to compile if the
529 # XCode 5.1 changes clang such that it now fails to compile if the
528 # -mno-fused-madd flag is passed, but the version of Python shipped with
530 # -mno-fused-madd flag is passed, but the version of Python shipped with
529 # OS X 10.9 Mavericks includes this flag. This causes problems in all
531 # OS X 10.9 Mavericks includes this flag. This causes problems in all
530 # C extension modules, and a bug has been filed upstream at
532 # C extension modules, and a bug has been filed upstream at
531 # http://bugs.python.org/issue21244. We also need to patch this here
533 # http://bugs.python.org/issue21244. We also need to patch this here
532 # so Mercurial can continue to compile in the meantime.
534 # so Mercurial can continue to compile in the meantime.
533 if xcode51:
535 if xcode51:
534 cflags = get_config_var('CFLAGS')
536 cflags = get_config_var('CFLAGS')
535 if re.search(r'-mno-fused-madd\b', cflags) is not None:
537 if re.search(r'-mno-fused-madd\b', cflags) is not None:
536 os.environ['CFLAGS'] = (
538 os.environ['CFLAGS'] = (
537 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
539 os.environ.get('CFLAGS', '') + ' -Qunused-arguments')
538
540
539 setup(name='mercurial',
541 setup(name='mercurial',
540 version=setupversion,
542 version=setupversion,
541 author='Matt Mackall and many others',
543 author='Matt Mackall and many others',
542 author_email='mercurial@selenic.com',
544 author_email='mercurial@selenic.com',
543 url='http://mercurial.selenic.com/',
545 url='http://mercurial.selenic.com/',
544 download_url='http://mercurial.selenic.com/release/',
546 download_url='http://mercurial.selenic.com/release/',
545 description=('Fast scalable distributed SCM (revision control, version '
547 description=('Fast scalable distributed SCM (revision control, version '
546 'control) system'),
548 'control) system'),
547 long_description=('Mercurial is a distributed SCM tool written in Python.'
549 long_description=('Mercurial is a distributed SCM tool written in Python.'
548 ' It is used by a number of large projects that require'
550 ' It is used by a number of large projects that require'
549 ' fast, reliable distributed revision control, such as '
551 ' fast, reliable distributed revision control, such as '
550 'Mozilla.'),
552 'Mozilla.'),
551 license='GNU GPLv2 or any later version',
553 license='GNU GPLv2 or any later version',
552 classifiers=[
554 classifiers=[
553 'Development Status :: 6 - Mature',
555 'Development Status :: 6 - Mature',
554 'Environment :: Console',
556 'Environment :: Console',
555 'Intended Audience :: Developers',
557 'Intended Audience :: Developers',
556 'Intended Audience :: System Administrators',
558 'Intended Audience :: System Administrators',
557 'License :: OSI Approved :: GNU General Public License (GPL)',
559 'License :: OSI Approved :: GNU General Public License (GPL)',
558 'Natural Language :: Danish',
560 'Natural Language :: Danish',
559 'Natural Language :: English',
561 'Natural Language :: English',
560 'Natural Language :: German',
562 'Natural Language :: German',
561 'Natural Language :: Italian',
563 'Natural Language :: Italian',
562 'Natural Language :: Japanese',
564 'Natural Language :: Japanese',
563 'Natural Language :: Portuguese (Brazilian)',
565 'Natural Language :: Portuguese (Brazilian)',
564 'Operating System :: Microsoft :: Windows',
566 'Operating System :: Microsoft :: Windows',
565 'Operating System :: OS Independent',
567 'Operating System :: OS Independent',
566 'Operating System :: POSIX',
568 'Operating System :: POSIX',
567 'Programming Language :: C',
569 'Programming Language :: C',
568 'Programming Language :: Python',
570 'Programming Language :: Python',
569 'Topic :: Software Development :: Version Control',
571 'Topic :: Software Development :: Version Control',
570 ],
572 ],
571 scripts=scripts,
573 scripts=scripts,
572 packages=packages,
574 packages=packages,
573 py_modules=pymodules,
575 py_modules=pymodules,
574 ext_modules=extmodules,
576 ext_modules=extmodules,
575 data_files=datafiles,
577 data_files=datafiles,
576 package_data=packagedata,
578 package_data=packagedata,
577 cmdclass=cmdclass,
579 cmdclass=cmdclass,
578 distclass=hgdist,
580 distclass=hgdist,
579 options={'py2exe': {'packages': ['hgext', 'email']},
581 options={'py2exe': {'packages': ['hgext', 'email']},
580 'bdist_mpkg': {'zipdist': True,
582 'bdist_mpkg': {'zipdist': True,
581 'license': 'COPYING',
583 'license': 'COPYING',
582 'readme': 'contrib/macosx/Readme.html',
584 'readme': 'contrib/macosx/Readme.html',
583 'welcome': 'contrib/macosx/Welcome.html',
585 'welcome': 'contrib/macosx/Welcome.html',
584 },
586 },
585 },
587 },
586 **extra)
588 **extra)
General Comments 0
You need to be logged in to leave comments. Login now