Show More
@@ -0,0 +1,92 b'' | |||||
|
1 | """utilities for checking submodule status""" | |||
|
2 | ||||
|
3 | #----------------------------------------------------------------------------- | |||
|
4 | # Copyright (C) 2013 The IPython Development Team | |||
|
5 | # | |||
|
6 | # Distributed under the terms of the BSD License. The full license is in | |||
|
7 | # the file COPYING, distributed as part of this software. | |||
|
8 | #----------------------------------------------------------------------------- | |||
|
9 | ||||
|
10 | #----------------------------------------------------------------------------- | |||
|
11 | # Imports | |||
|
12 | #----------------------------------------------------------------------------- | |||
|
13 | ||||
|
14 | import os | |||
|
15 | import subprocess | |||
|
16 | import sys | |||
|
17 | ||||
|
18 | #----------------------------------------------------------------------------- | |||
|
19 | # Globals | |||
|
20 | #----------------------------------------------------------------------------- | |||
|
21 | ||||
|
22 | pjoin = os.path.join | |||
|
23 | ||||
|
24 | #----------------------------------------------------------------------------- | |||
|
25 | # Code | |||
|
26 | #----------------------------------------------------------------------------- | |||
|
27 | ||||
|
28 | def ipython_parent(): | |||
|
29 | """return IPython's parent (i.e. root if run from git)""" | |||
|
30 | from IPython.utils.path import get_ipython_package_dir | |||
|
31 | return os.path.abspath(os.path.dirname(get_ipython_package_dir())) | |||
|
32 | ||||
|
33 | def ipython_submodules(root): | |||
|
34 | """return IPython submodules relative to root""" | |||
|
35 | return [ | |||
|
36 | pjoin(root, 'IPython', 'frontend', 'html', 'notebook', 'static', 'components'), | |||
|
37 | ] | |||
|
38 | ||||
|
39 | def is_repo(d): | |||
|
40 | """is d a git repo?""" | |||
|
41 | return os.path.exists(pjoin(d, '.git')) | |||
|
42 | ||||
|
43 | def check_submodule_status(root=None): | |||
|
44 | """check submodule status | |||
|
45 | ||||
|
46 | Has three return values: | |||
|
47 | ||||
|
48 | 'missing' - submodules are absent | |||
|
49 | 'unclean' - submodules have unstaged changes | |||
|
50 | 'clean' - all submodules are up to date | |||
|
51 | """ | |||
|
52 | ||||
|
53 | if hasattr(sys, "frozen"): | |||
|
54 | # frozen via py2exe or similar, don't bother | |||
|
55 | return 'clean' | |||
|
56 | ||||
|
57 | if not root: | |||
|
58 | root = ipython_parent() | |||
|
59 | ||||
|
60 | submodules = ipython_submodules(root) | |||
|
61 | ||||
|
62 | for submodule in submodules: | |||
|
63 | if not os.path.exists(submodule): | |||
|
64 | return 'missing' | |||
|
65 | ||||
|
66 | if not is_repo(root): | |||
|
67 | # not in git, assume clean | |||
|
68 | return 'clean' | |||
|
69 | ||||
|
70 | # check with git submodule status | |||
|
71 | proc = subprocess.Popen('git submodule status', | |||
|
72 | stdout=subprocess.PIPE, | |||
|
73 | stderr=subprocess.PIPE, | |||
|
74 | shell=True, | |||
|
75 | cwd=root, | |||
|
76 | ) | |||
|
77 | status, _ = proc.communicate() | |||
|
78 | status = status.decode("ascii") | |||
|
79 | ||||
|
80 | for line in status.splitlines(): | |||
|
81 | if status.startswith('-'): | |||
|
82 | return 'missing' | |||
|
83 | elif status.startswith('+'): | |||
|
84 | return 'unclean' | |||
|
85 | ||||
|
86 | return 'clean' | |||
|
87 | ||||
|
88 | def update_submodules(repo_dir): | |||
|
89 | """update submodules in a repo""" | |||
|
90 | subprocess.check_call("git submodule init", cwd=repo_dir, shell=True) | |||
|
91 | subprocess.check_call("git submodule update --recursive", cwd=repo_dir, shell=True) | |||
|
92 |
@@ -0,0 +1,13 b'' | |||||
|
1 | git hooks for IPython | |||
|
2 | ||||
|
3 | add these to your `.git/hooks` | |||
|
4 | ||||
|
5 | For now, we just have `post-checkout` and `post-merge`, | |||
|
6 | both of which just update submodules, | |||
|
7 | so make sure that you have a fully synced repo whenever you checkout or pull. | |||
|
8 | ||||
|
9 | To use these hooks, you can symlink or copy them to your `.git/hooks` directory. | |||
|
10 | ||||
|
11 | ln -s ../../git-hooks/post-checkout .git/hooks/post-checkout | |||
|
12 | ln -s ../../git-hooks/post-merge .git/hooks/post-merge | |||
|
13 |
@@ -95,6 +95,26 b' def catch_config_error(method, app, *args, **kwargs):' | |||||
95 | class ApplicationError(Exception): |
|
95 | class ApplicationError(Exception): | |
96 | pass |
|
96 | pass | |
97 |
|
97 | |||
|
98 | class LevelFormatter(logging.Formatter): | |||
|
99 | """Formatter with additional `highlevel` record | |||
|
100 | ||||
|
101 | This field is empty if log level is less than highlevel_limit, | |||
|
102 | otherwise it is formatted with self.highlevel_format. | |||
|
103 | ||||
|
104 | Useful for adding 'WARNING' to warning messages, | |||
|
105 | without adding 'INFO' to info, etc. | |||
|
106 | """ | |||
|
107 | highlevel_limit = logging.WARN | |||
|
108 | highlevel_format = " %(levelname)s |" | |||
|
109 | ||||
|
110 | def format(self, record): | |||
|
111 | if record.levelno >= self.highlevel_limit: | |||
|
112 | record.highlevel = self.highlevel_format % record.__dict__ | |||
|
113 | else: | |||
|
114 | record.highlevel = "" | |||
|
115 | ||||
|
116 | return super(LevelFormatter, self).format(record) | |||
|
117 | ||||
98 |
|
118 | |||
99 | class Application(SingletonConfigurable): |
|
119 | class Application(SingletonConfigurable): | |
100 | """A singleton application with full configuration support.""" |
|
120 | """A singleton application with full configuration support.""" | |
@@ -133,13 +153,19 b' class Application(SingletonConfigurable):' | |||||
133 | self.log_level = new |
|
153 | self.log_level = new | |
134 | self.log.setLevel(new) |
|
154 | self.log.setLevel(new) | |
135 |
|
155 | |||
136 |
log_f |
|
156 | log_datefmt = Unicode("%Y-%m-%d %H:%M:%S", config=True, | |
|
157 | help="The date format used by logging formatters for %(asctime)s" | |||
|
158 | ) | |||
|
159 | def _log_datefmt_changed(self, name, old, new): | |||
|
160 | self._log_format_changed() | |||
|
161 | ||||
|
162 | log_format = Unicode("[%(name)s]%(highlevel)s %(message)s", config=True, | |||
137 | help="The Logging format template", |
|
163 | help="The Logging format template", | |
138 | ) |
|
164 | ) | |
139 | def _log_format_changed(self, name, old, new): |
|
165 | def _log_format_changed(self, name, old, new): | |
140 | """Change the log formatter when log_format is set.""" |
|
166 | """Change the log formatter when log_format is set.""" | |
141 | _log_handler = self.log.handlers[0] |
|
167 | _log_handler = self.log.handlers[0] | |
142 |
_log_formatter = l |
|
168 | _log_formatter = LevelFormatter(new, datefmt=self._log_datefmt) | |
143 | _log_handler.setFormatter(_log_formatter) |
|
169 | _log_handler.setFormatter(_log_formatter) | |
144 |
|
170 | |||
145 | log = Instance(logging.Logger) |
|
171 | log = Instance(logging.Logger) | |
@@ -167,7 +193,7 b' class Application(SingletonConfigurable):' | |||||
167 | _log_handler = logging.StreamHandler(open(os.devnull, 'w')) |
|
193 | _log_handler = logging.StreamHandler(open(os.devnull, 'w')) | |
168 | else: |
|
194 | else: | |
169 | _log_handler = logging.StreamHandler() |
|
195 | _log_handler = logging.StreamHandler() | |
170 |
_log_formatter = l |
|
196 | _log_formatter = LevelFormatter(self.log_format, datefmt=self.log_datefmt) | |
171 | _log_handler.setFormatter(_log_formatter) |
|
197 | _log_handler.setFormatter(_log_formatter) | |
172 | log.addHandler(_log_handler) |
|
198 | log.addHandler(_log_handler) | |
173 | return log |
|
199 | return log |
@@ -6,7 +6,7 b' Authors:' | |||||
6 | * Brian Granger |
|
6 | * Brian Granger | |
7 | """ |
|
7 | """ | |
8 | #----------------------------------------------------------------------------- |
|
8 | #----------------------------------------------------------------------------- | |
9 |
# Copyright (C) 20 |
|
9 | # Copyright (C) 2013 The IPython Development Team | |
10 | # |
|
10 | # | |
11 | # Distributed under the terms of the BSD License. The full license is in |
|
11 | # Distributed under the terms of the BSD License. The full license is in | |
12 | # the file COPYING, distributed as part of this software. |
|
12 | # the file COPYING, distributed as part of this software. | |
@@ -90,6 +90,7 b' from IPython.kernel.zmq.kernelapp import (' | |||||
90 | ) |
|
90 | ) | |
91 | from IPython.utils.importstring import import_item |
|
91 | from IPython.utils.importstring import import_item | |
92 | from IPython.utils.localinterfaces import LOCALHOST |
|
92 | from IPython.utils.localinterfaces import LOCALHOST | |
|
93 | from IPython.utils import submodule | |||
93 | from IPython.utils.traitlets import ( |
|
94 | from IPython.utils.traitlets import ( | |
94 | Dict, Unicode, Integer, List, Enum, Bool, |
|
95 | Dict, Unicode, Integer, List, Enum, Bool, | |
95 | DottedObjectName |
|
96 | DottedObjectName | |
@@ -323,7 +324,7 b' class NotebookApp(BaseIPythonApplication):' | |||||
323 |
|
324 | |||
324 | def _log_format_default(self): |
|
325 | def _log_format_default(self): | |
325 | """override default log format to include time""" |
|
326 | """override default log format to include time""" | |
326 | return u"%(asctime)s.%(msecs).03d [%(name)s] %(message)s" |
|
327 | return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s" | |
327 |
|
328 | |||
328 | # create requested profiles by default, if they don't exist: |
|
329 | # create requested profiles by default, if they don't exist: | |
329 | auto_create = Bool(True) |
|
330 | auto_create = Bool(True) | |
@@ -537,10 +538,6 b' class NotebookApp(BaseIPythonApplication):' | |||||
537 | # and all of its ancenstors until propagate is set to False. |
|
538 | # and all of its ancenstors until propagate is set to False. | |
538 | self.log.propagate = False |
|
539 | self.log.propagate = False | |
539 |
|
540 | |||
540 | # set the date format |
|
|||
541 | formatter = logging.Formatter(self.log_format, datefmt="%Y-%m-%d %H:%M:%S") |
|
|||
542 | self.log.handlers[0].setFormatter(formatter) |
|
|||
543 |
|
||||
544 | # hook up tornado 3's loggers to our app handlers |
|
541 | # hook up tornado 3's loggers to our app handlers | |
545 | for name in ('access', 'application', 'general'): |
|
542 | for name in ('access', 'application', 'general'): | |
546 | logging.getLogger('tornado.%s' % name).handlers = self.log.handlers |
|
543 | logging.getLogger('tornado.%s' % name).handlers = self.log.handlers | |
@@ -673,11 +670,23 b' class NotebookApp(BaseIPythonApplication):' | |||||
673 | def _signal_info(self, sig, frame): |
|
670 | def _signal_info(self, sig, frame): | |
674 | print self.notebook_info() |
|
671 | print self.notebook_info() | |
675 |
|
672 | |||
|
673 | def init_components(self): | |||
|
674 | """Check the components submodule, and warn if it's unclean""" | |||
|
675 | status = submodule.check_submodule_status() | |||
|
676 | if status == 'missing': | |||
|
677 | self.log.warn("components submodule missing, running `git submodule update`") | |||
|
678 | submodule.update_submodules(submodule.ipython_parent()) | |||
|
679 | elif status == 'unclean': | |||
|
680 | self.log.warn("components submodule unclean, you may see 404s on static/components") | |||
|
681 | self.log.warn("run `setup.py submodule` or `git submodule update` to update") | |||
|
682 | ||||
|
683 | ||||
676 | @catch_config_error |
|
684 | @catch_config_error | |
677 | def initialize(self, argv=None): |
|
685 | def initialize(self, argv=None): | |
678 | self.init_logging() |
|
686 | self.init_logging() | |
679 | super(NotebookApp, self).initialize(argv) |
|
687 | super(NotebookApp, self).initialize(argv) | |
680 | self.init_configurables() |
|
688 | self.init_configurables() | |
|
689 | self.init_components() | |||
681 | self.init_webapp() |
|
690 | self.init_webapp() | |
682 | self.init_signal() |
|
691 | self.init_signal() | |
683 |
|
692 |
@@ -307,10 +307,6 b' class IPKernelApp(BaseIPythonApplication, InteractiveShellApp):' | |||||
307 | self.hb_port = self.heartbeat.port |
|
307 | self.hb_port = self.heartbeat.port | |
308 | self.log.debug("Heartbeat REP Channel on port: %i" % self.hb_port) |
|
308 | self.log.debug("Heartbeat REP Channel on port: %i" % self.hb_port) | |
309 | self.heartbeat.start() |
|
309 | self.heartbeat.start() | |
310 |
|
||||
311 | # Helper to make it easier to connect to an existing kernel. |
|
|||
312 | # set log-level to critical, to make sure it is output |
|
|||
313 | self.log.critical("To connect another client to this kernel, use:") |
|
|||
314 |
|
310 | |||
315 | def log_connection_info(self): |
|
311 | def log_connection_info(self): | |
316 | """display connection info, and store ports""" |
|
312 | """display connection info, and store ports""" | |
@@ -323,8 +319,20 b' class IPKernelApp(BaseIPythonApplication, InteractiveShellApp):' | |||||
323 | tail += " --profile %s" % self.profile |
|
319 | tail += " --profile %s" % self.profile | |
324 | else: |
|
320 | else: | |
325 | tail = self.connection_file |
|
321 | tail = self.connection_file | |
326 | self.log.critical("--existing %s", tail) |
|
322 | lines = [ | |
327 |
|
323 | "To connect another client to this kernel, use:", | ||
|
324 | " --existing %s" % tail, | |||
|
325 | ] | |||
|
326 | # log connection info | |||
|
327 | # info-level, so often not shown. | |||
|
328 | # frontends should use the %connect_info magic | |||
|
329 | # to see the connection info | |||
|
330 | for line in lines: | |||
|
331 | self.log.info(line) | |||
|
332 | # also raw print to the terminal if no parent (`ipython kernel`) | |||
|
333 | if not self.parent: | |||
|
334 | for line in lines: | |||
|
335 | io.rprint(line) | |||
328 |
|
336 | |||
329 | self.ports = dict(shell=self.shell_port, iopub=self.iopub_port, |
|
337 | self.ports = dict(shell=self.shell_port, iopub=self.iopub_port, | |
330 | stdin=self.stdin_port, hb=self.hb_port, |
|
338 | stdin=self.stdin_port, hb=self.hb_port, |
@@ -29,7 +29,7 b' import sys' | |||||
29 |
|
29 | |||
30 | from subprocess import Popen, PIPE |
|
30 | from subprocess import Popen, PIPE | |
31 |
|
31 | |||
32 | from IPython.config.application import catch_config_error |
|
32 | from IPython.config.application import catch_config_error, LevelFormatter | |
33 | from IPython.core import release |
|
33 | from IPython.core import release | |
34 | from IPython.core.crashhandler import CrashHandler |
|
34 | from IPython.core.crashhandler import CrashHandler | |
35 | from IPython.core.application import ( |
|
35 | from IPython.core.application import ( | |
@@ -105,7 +105,7 b' class BaseParallelApplication(BaseIPythonApplication):' | |||||
105 |
|
105 | |||
106 | def _log_format_default(self): |
|
106 | def _log_format_default(self): | |
107 | """override default log format to include time""" |
|
107 | """override default log format to include time""" | |
108 | return u"%(asctime)s.%(msecs).03d [%(name)s] %(message)s" |
|
108 | return u"%(asctime)s.%(msecs).03d [%(name)s]%(highlevel)s %(message)s" | |
109 |
|
109 | |||
110 | work_dir = Unicode(os.getcwdu(), config=True, |
|
110 | work_dir = Unicode(os.getcwdu(), config=True, | |
111 | help='Set the working dir for the process.' |
|
111 | help='Set the working dir for the process.' | |
@@ -191,8 +191,8 b' class BaseParallelApplication(BaseIPythonApplication):' | |||||
191 | else: |
|
191 | else: | |
192 | self._log_handler = self.log.handlers[0] |
|
192 | self._log_handler = self.log.handlers[0] | |
193 | # Add timestamps to log format: |
|
193 | # Add timestamps to log format: | |
194 |
self._log_formatter = l |
|
194 | self._log_formatter = LevelFormatter(self.log_format, | |
195 |
datefmt= |
|
195 | datefmt=self.log_datefmt) | |
196 | self._log_handler.setFormatter(self._log_formatter) |
|
196 | self._log_handler.setFormatter(self._log_formatter) | |
197 | # do not propagate log messages to root logger |
|
197 | # do not propagate log messages to root logger | |
198 | # ipcluster app will sometimes print duplicate messages during shutdown |
|
198 | # ipcluster app will sometimes print duplicate messages during shutdown |
@@ -47,3 +47,18 b' environment so that you can work on your local repo copy and run it from anywher' | |||||
47 |
|
47 | |||
48 | The same process applies for other parts, such as the qtconsole (the |
|
48 | The same process applies for other parts, such as the qtconsole (the | |
49 | ``extras_require`` attribute in the setup.py file lists all the possibilities). |
|
49 | ``extras_require`` attribute in the setup.py file lists all the possibilities). | |
|
50 | ||||
|
51 | Git Hooks and Submodules | |||
|
52 | ************************ | |||
|
53 | ||||
|
54 | IPython now uses git submodules to ship its javascript dependencies. | |||
|
55 | If you run IPython from git master, you may need to update submodules once in a while with:: | |||
|
56 | ||||
|
57 | $ git submodule update | |||
|
58 | ||||
|
59 | or:: | |||
|
60 | ||||
|
61 | $ python setup.py submodule | |||
|
62 | ||||
|
63 | We have some git hooks for helping keep your submodules always in sync, | |||
|
64 | see our ``git-hooks`` directory for more info. |
@@ -68,7 +68,7 b' from setupbase import (' | |||||
68 | find_data_files, |
|
68 | find_data_files, | |
69 | check_for_dependencies, |
|
69 | check_for_dependencies, | |
70 | git_prebuild, |
|
70 | git_prebuild, | |
71 |
check_ |
|
71 | check_submodule_status, | |
72 | update_submodules, |
|
72 | update_submodules, | |
73 | require_submodules, |
|
73 | require_submodules, | |
74 | UpdateSubmodules, |
|
74 | UpdateSubmodules, | |
@@ -112,21 +112,37 b" if os_name == 'windows' and 'sdist' in sys.argv:" | |||||
112 | #------------------------------------------------------------------------------- |
|
112 | #------------------------------------------------------------------------------- | |
113 | # Make sure we aren't trying to run without submodules |
|
113 | # Make sure we aren't trying to run without submodules | |
114 | #------------------------------------------------------------------------------- |
|
114 | #------------------------------------------------------------------------------- | |
|
115 | here = os.path.abspath(os.path.dirname(__file__)) | |||
115 |
|
116 | |||
116 |
def |
|
117 | def require_clean_submodules(): | |
117 |
"""Check o |
|
118 | """Check on git submodules before distutils can do anything | |
118 |
|
119 | |||
119 |
|
|
120 | Since distutils cannot be trusted to update the tree | |
120 |
after everything has been set in motion |
|
121 | after everything has been set in motion, | |
|
122 | this is not a distutils command. | |||
121 | """ |
|
123 | """ | |
122 | # don't do anything if nothing is actually supposed to happen |
|
124 | # don't do anything if nothing is actually supposed to happen | |
123 | for do_nothing in ('-h', '--help', '--help-commands', 'clean'): |
|
125 | for do_nothing in ('-h', '--help', '--help-commands', 'clean', 'submodule'): | |
124 | if do_nothing in sys.argv: |
|
126 | if do_nothing in sys.argv: | |
125 | return |
|
127 | return | |
126 | if not check_for_submodules(): |
|
|||
127 | update_submodules() |
|
|||
128 |
|
128 | |||
129 | ensure_submodules_exist() |
|
129 | status = check_submodule_status(here) | |
|
130 | ||||
|
131 | if status == "missing": | |||
|
132 | print("checking out submodules for the first time") | |||
|
133 | update_submodules(here) | |||
|
134 | elif status == "unclean": | |||
|
135 | print('\n'.join([ | |||
|
136 | "Cannot build / install IPython with unclean submodules", | |||
|
137 | "Please update submodules with", | |||
|
138 | " python setup.py submodule", | |||
|
139 | "or", | |||
|
140 | " git submodule update", | |||
|
141 | "or commit any submodule changes you have made." | |||
|
142 | ])) | |||
|
143 | sys.exit(1) | |||
|
144 | ||||
|
145 | require_clean_submodules() | |||
130 |
|
146 | |||
131 | #------------------------------------------------------------------------------- |
|
147 | #------------------------------------------------------------------------------- | |
132 | # Things related to the IPython documentation |
|
148 | # Things related to the IPython documentation |
@@ -373,27 +373,10 b' def check_for_dependencies():' | |||||
373 | # VCS related |
|
373 | # VCS related | |
374 | #--------------------------------------------------------------------------- |
|
374 | #--------------------------------------------------------------------------- | |
375 |
|
375 | |||
376 | def check_for_submodules(): |
|
376 | here = os.path.abspath(os.path.dirname(__file__)) | |
377 | """return False if there are any submodules that need to be checked out, |
|
|||
378 | True otherwise. |
|
|||
379 |
|
||||
380 | This doesn't check if they are up to date, only existence. |
|
|||
381 | """ |
|
|||
382 | here = os.path.dirname(__file__) |
|
|||
383 | submodules = [ |
|
|||
384 | os.path.join(here, 'IPython', 'frontend', 'html', 'notebook', 'static', 'components') |
|
|||
385 | ] |
|
|||
386 | for submodule in submodules: |
|
|||
387 | if not os.path.exists(submodule): |
|
|||
388 | return False |
|
|||
389 | return True |
|
|||
390 |
|
377 | |||
391 | def update_submodules(): |
|
378 | # utils.submodule has checks for submodule status | |
392 | """update git submodules""" |
|
379 | execfile(pjoin('IPython','utils','submodule.py'), globals()) | |
393 | import subprocess |
|
|||
394 | print("updating git submodules") |
|
|||
395 | subprocess.check_call('git submodule init'.split()) |
|
|||
396 | subprocess.check_call('git submodule update --recursive'.split()) |
|
|||
397 |
|
380 | |||
398 | class UpdateSubmodules(Command): |
|
381 | class UpdateSubmodules(Command): | |
399 | """Update git submodules |
|
382 | """Update git submodules | |
@@ -418,12 +401,10 b' class UpdateSubmodules(Command):' | |||||
418 | failure = e |
|
401 | failure = e | |
419 | print(e) |
|
402 | print(e) | |
420 |
|
403 | |||
421 |
if not check_ |
|
404 | if not check_submodule_status(here) == 'clean': | |
422 | print("submodules could not be checked out") |
|
405 | print("submodules could not be checked out") | |
423 | sys.exit(1) |
|
406 | sys.exit(1) | |
424 |
|
407 | |||
425 | # re-scan package data after update |
|
|||
426 | self.distribution.package_data = find_package_data() |
|
|||
427 |
|
408 | |||
428 | def git_prebuild(pkg_dir, build_cmd=build_py): |
|
409 | def git_prebuild(pkg_dir, build_cmd=build_py): | |
429 | """Return extended build or sdist command class for recording commit |
|
410 | """Return extended build or sdist command class for recording commit | |
@@ -438,10 +419,6 b' def git_prebuild(pkg_dir, build_cmd=build_py):' | |||||
438 | class MyBuildPy(build_cmd): |
|
419 | class MyBuildPy(build_cmd): | |
439 | ''' Subclass to write commit data into installation tree ''' |
|
420 | ''' Subclass to write commit data into installation tree ''' | |
440 | def run(self): |
|
421 | def run(self): | |
441 | if not check_for_submodules(): |
|
|||
442 | print("submodules missing! Run `setup.py submodule` and try again") |
|
|||
443 | sys.exit(1) |
|
|||
444 |
|
||||
445 | build_cmd.run(self) |
|
422 | build_cmd.run(self) | |
446 | # this one will only fire for build commands |
|
423 | # this one will only fire for build commands | |
447 | if hasattr(self, 'build_lib'): |
|
424 | if hasattr(self, 'build_lib'): | |
@@ -478,14 +455,14 b' def git_prebuild(pkg_dir, build_cmd=build_py):' | |||||
478 | '# GENERATED BY setup.py\n', |
|
455 | '# GENERATED BY setup.py\n', | |
479 | 'commit = "%s"\n' % repo_commit, |
|
456 | 'commit = "%s"\n' % repo_commit, | |
480 | ]) |
|
457 | ]) | |
481 | return MyBuildPy |
|
458 | return require_submodules(MyBuildPy) | |
482 |
|
459 | |||
483 |
|
460 | |||
484 | def require_submodules(command): |
|
461 | def require_submodules(command): | |
485 | """decorator for instructing a command to check for submodules before running""" |
|
462 | """decorator for instructing a command to check for submodules before running""" | |
486 | class DecoratedCommand(command): |
|
463 | class DecoratedCommand(command): | |
487 | def run(self): |
|
464 | def run(self): | |
488 |
if not check_ |
|
465 | if not check_submodule_status(here) == 'clean': | |
489 | print("submodules missing! Run `setup.py submodule` and try again") |
|
466 | print("submodules missing! Run `setup.py submodule` and try again") | |
490 | sys.exit(1) |
|
467 | sys.exit(1) | |
491 | command.run(self) |
|
468 | command.run(self) |
General Comments 0
You need to be logged in to leave comments.
Login now