##// END OF EJS Templates
Added option to re-install githooks to repo2db mapper, and catch exception on removal so it doesn't break...
marcink -
r2619:f1dfd3a2 beta
parent child Browse files
Show More
@@ -1,685 +1,697 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 rhodecode.lib.utils
4 4 ~~~~~~~~~~~~~~~~~~~
5 5
6 6 Utilities library for RhodeCode
7 7
8 8 :created_on: Apr 18, 2010
9 9 :author: marcink
10 10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 11 :license: GPLv3, see COPYING for more details.
12 12 """
13 13 # This program is free software: you can redistribute it and/or modify
14 14 # it under the terms of the GNU General Public License as published by
15 15 # the Free Software Foundation, either version 3 of the License, or
16 16 # (at your option) any later version.
17 17 #
18 18 # This program is distributed in the hope that it will be useful,
19 19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 21 # GNU General Public License for more details.
22 22 #
23 23 # You should have received a copy of the GNU General Public License
24 24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 25
26 26 import os
27 27 import re
28 28 import logging
29 29 import datetime
30 30 import traceback
31 31 import paste
32 32 import beaker
33 33 import tarfile
34 34 import shutil
35 35 from os.path import abspath
36 36 from os.path import dirname as dn, join as jn
37 37
38 38 from paste.script.command import Command, BadCommand
39 39
40 40 from mercurial import ui, config
41 41
42 42 from webhelpers.text import collapse, remove_formatting, strip_tags
43 43
44 44 from rhodecode.lib.vcs import get_backend
45 45 from rhodecode.lib.vcs.backends.base import BaseChangeset
46 46 from rhodecode.lib.vcs.utils.lazy import LazyProperty
47 47 from rhodecode.lib.vcs.utils.helpers import get_scm
48 48 from rhodecode.lib.vcs.exceptions import VCSError
49 49
50 50 from rhodecode.lib.caching_query import FromCache
51 51
52 52 from rhodecode.model import meta
53 53 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
54 54 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation
55 55 from rhodecode.model.meta import Session
56 56 from rhodecode.model.repos_group import ReposGroupModel
57 57 from rhodecode.lib.utils2 import safe_str, safe_unicode
58 58 from rhodecode.lib.vcs.utils.fakemod import create_module
59 59
60 60 log = logging.getLogger(__name__)
61 61
62 62 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
63 63
64 64
65 65 def recursive_replace(str_, replace=' '):
66 66 """
67 67 Recursive replace of given sign to just one instance
68 68
69 69 :param str_: given string
70 70 :param replace: char to find and replace multiple instances
71 71
72 72 Examples::
73 73 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
74 74 'Mighty-Mighty-Bo-sstones'
75 75 """
76 76
77 77 if str_.find(replace * 2) == -1:
78 78 return str_
79 79 else:
80 80 str_ = str_.replace(replace * 2, replace)
81 81 return recursive_replace(str_, replace)
82 82
83 83
84 84 def repo_name_slug(value):
85 85 """
86 86 Return slug of name of repository
87 87 This function is called on each creation/modification
88 88 of repository to prevent bad names in repo
89 89 """
90 90
91 91 slug = remove_formatting(value)
92 92 slug = strip_tags(slug)
93 93
94 94 for c in """=[]\;'"<>,/~!@#$%^&*()+{}|: """:
95 95 slug = slug.replace(c, '-')
96 96 slug = recursive_replace(slug, '-')
97 97 slug = collapse(slug, '-')
98 98 return slug
99 99
100 100
101 101 def get_repo_slug(request):
102 102 _repo = request.environ['pylons.routes_dict'].get('repo_name')
103 103 if _repo:
104 104 _repo = _repo.rstrip('/')
105 105 return _repo
106 106
107 107
108 108 def get_repos_group_slug(request):
109 109 _group = request.environ['pylons.routes_dict'].get('group_name')
110 110 if _group:
111 111 _group = _group.rstrip('/')
112 112 return _group
113 113
114 114
115 115 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
116 116 """
117 117 Action logger for various actions made by users
118 118
119 119 :param user: user that made this action, can be a unique username string or
120 120 object containing user_id attribute
121 121 :param action: action to log, should be on of predefined unique actions for
122 122 easy translations
123 123 :param repo: string name of repository or object containing repo_id,
124 124 that action was made on
125 125 :param ipaddr: optional ip address from what the action was made
126 126 :param sa: optional sqlalchemy session
127 127
128 128 """
129 129
130 130 if not sa:
131 131 sa = meta.Session()
132 132
133 133 try:
134 134 if hasattr(user, 'user_id'):
135 135 user_obj = user
136 136 elif isinstance(user, basestring):
137 137 user_obj = User.get_by_username(user)
138 138 else:
139 139 raise Exception('You have to provide user object or username')
140 140
141 141 if hasattr(repo, 'repo_id'):
142 142 repo_obj = Repository.get(repo.repo_id)
143 143 repo_name = repo_obj.repo_name
144 144 elif isinstance(repo, basestring):
145 145 repo_name = repo.lstrip('/')
146 146 repo_obj = Repository.get_by_repo_name(repo_name)
147 147 else:
148 148 repo_obj = None
149 149 repo_name = ''
150 150
151 151 user_log = UserLog()
152 152 user_log.user_id = user_obj.user_id
153 153 user_log.action = safe_unicode(action)
154 154
155 155 user_log.repository = repo_obj
156 156 user_log.repository_name = repo_name
157 157
158 158 user_log.action_date = datetime.datetime.now()
159 159 user_log.user_ip = ipaddr
160 160 sa.add(user_log)
161 161
162 162 log.info(
163 163 'Adding user %s, action %s on %s' % (user_obj, action,
164 164 safe_unicode(repo))
165 165 )
166 166 if commit:
167 167 sa.commit()
168 168 except:
169 169 log.error(traceback.format_exc())
170 170 raise
171 171
172 172
173 173 def get_repos(path, recursive=False):
174 174 """
175 175 Scans given path for repos and return (name,(type,path)) tuple
176 176
177 177 :param path: path to scan for repositories
178 178 :param recursive: recursive search and return names with subdirs in front
179 179 """
180 180
181 181 # remove ending slash for better results
182 182 path = path.rstrip(os.sep)
183 183
184 184 def _get_repos(p):
185 185 if not os.access(p, os.W_OK):
186 186 return
187 187 for dirpath in os.listdir(p):
188 188 if os.path.isfile(os.path.join(p, dirpath)):
189 189 continue
190 190 cur_path = os.path.join(p, dirpath)
191 191 try:
192 192 scm_info = get_scm(cur_path)
193 193 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
194 194 except VCSError:
195 195 if not recursive:
196 196 continue
197 197 #check if this dir containts other repos for recursive scan
198 198 rec_path = os.path.join(p, dirpath)
199 199 if os.path.isdir(rec_path):
200 200 for inner_scm in _get_repos(rec_path):
201 201 yield inner_scm
202 202
203 203 return _get_repos(path)
204 204
205 205
206 206 def is_valid_repo(repo_name, base_path):
207 207 """
208 208 Returns True if given path is a valid repository False otherwise
209 209
210 210 :param repo_name:
211 211 :param base_path:
212 212
213 213 :return True: if given path is a valid repository
214 214 """
215 215 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
216 216
217 217 try:
218 218 get_scm(full_path)
219 219 return True
220 220 except VCSError:
221 221 return False
222 222
223 223
224 224 def is_valid_repos_group(repos_group_name, base_path):
225 225 """
226 226 Returns True if given path is a repos group False otherwise
227 227
228 228 :param repo_name:
229 229 :param base_path:
230 230 """
231 231 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
232 232
233 233 # check if it's not a repo
234 234 if is_valid_repo(repos_group_name, base_path):
235 235 return False
236 236
237 237 try:
238 238 # we need to check bare git repos at higher level
239 239 # since we might match branches/hooks/info/objects or possible
240 240 # other things inside bare git repo
241 241 get_scm(os.path.dirname(full_path))
242 242 return False
243 243 except VCSError:
244 244 pass
245 245
246 246 # check if it's a valid path
247 247 if os.path.isdir(full_path):
248 248 return True
249 249
250 250 return False
251 251
252 252
253 253 def ask_ok(prompt, retries=4, complaint='Yes or no, please!'):
254 254 while True:
255 255 ok = raw_input(prompt)
256 256 if ok in ('y', 'ye', 'yes'):
257 257 return True
258 258 if ok in ('n', 'no', 'nop', 'nope'):
259 259 return False
260 260 retries = retries - 1
261 261 if retries < 0:
262 262 raise IOError
263 263 print complaint
264 264
265 265 #propagated from mercurial documentation
266 266 ui_sections = ['alias', 'auth',
267 267 'decode/encode', 'defaults',
268 268 'diff', 'email',
269 269 'extensions', 'format',
270 270 'merge-patterns', 'merge-tools',
271 271 'hooks', 'http_proxy',
272 272 'smtp', 'patch',
273 273 'paths', 'profiling',
274 274 'server', 'trusted',
275 275 'ui', 'web', ]
276 276
277 277
278 278 def make_ui(read_from='file', path=None, checkpaths=True):
279 279 """
280 280 A function that will read python rc files or database
281 281 and make an mercurial ui object from read options
282 282
283 283 :param path: path to mercurial config file
284 284 :param checkpaths: check the path
285 285 :param read_from: read from 'file' or 'db'
286 286 """
287 287
288 288 baseui = ui.ui()
289 289
290 290 # clean the baseui object
291 291 baseui._ocfg = config.config()
292 292 baseui._ucfg = config.config()
293 293 baseui._tcfg = config.config()
294 294
295 295 if read_from == 'file':
296 296 if not os.path.isfile(path):
297 297 log.debug('hgrc file is not present at %s skipping...' % path)
298 298 return False
299 299 log.debug('reading hgrc from %s' % path)
300 300 cfg = config.config()
301 301 cfg.read(path)
302 302 for section in ui_sections:
303 303 for k, v in cfg.items(section):
304 304 log.debug('settings ui from file[%s]%s:%s' % (section, k, v))
305 305 baseui.setconfig(section, k, v)
306 306
307 307 elif read_from == 'db':
308 308 sa = meta.Session()
309 309 ret = sa.query(RhodeCodeUi)\
310 310 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
311 311 .all()
312 312
313 313 hg_ui = ret
314 314 for ui_ in hg_ui:
315 315 if ui_.ui_active:
316 316 log.debug('settings ui from db[%s]%s:%s', ui_.ui_section,
317 317 ui_.ui_key, ui_.ui_value)
318 318 baseui.setconfig(ui_.ui_section, ui_.ui_key, ui_.ui_value)
319 319
320 320 meta.Session.remove()
321 321 return baseui
322 322
323 323
324 324 def set_rhodecode_config(config):
325 325 """
326 326 Updates pylons config with new settings from database
327 327
328 328 :param config:
329 329 """
330 330 hgsettings = RhodeCodeSetting.get_app_settings()
331 331
332 332 for k, v in hgsettings.items():
333 333 config[k] = v
334 334
335 335
336 336 def invalidate_cache(cache_key, *args):
337 337 """
338 338 Puts cache invalidation task into db for
339 339 further global cache invalidation
340 340 """
341 341
342 342 from rhodecode.model.scm import ScmModel
343 343
344 344 if cache_key.startswith('get_repo_cached_'):
345 345 name = cache_key.split('get_repo_cached_')[-1]
346 346 ScmModel().mark_for_invalidation(name)
347 347
348 348
349 349 class EmptyChangeset(BaseChangeset):
350 350 """
351 351 An dummy empty changeset. It's possible to pass hash when creating
352 352 an EmptyChangeset
353 353 """
354 354
355 355 def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
356 356 alias=None):
357 357 self._empty_cs = cs
358 358 self.revision = -1
359 359 self.message = ''
360 360 self.author = ''
361 361 self.date = ''
362 362 self.repository = repo
363 363 self.requested_revision = requested_revision
364 364 self.alias = alias
365 365
366 366 @LazyProperty
367 367 def raw_id(self):
368 368 """
369 369 Returns raw string identifying this changeset, useful for web
370 370 representation.
371 371 """
372 372
373 373 return self._empty_cs
374 374
375 375 @LazyProperty
376 376 def branch(self):
377 377 return get_backend(self.alias).DEFAULT_BRANCH_NAME
378 378
379 379 @LazyProperty
380 380 def short_id(self):
381 381 return self.raw_id[:12]
382 382
383 383 def get_file_changeset(self, path):
384 384 return self
385 385
386 386 def get_file_content(self, path):
387 387 return u''
388 388
389 389 def get_file_size(self, path):
390 390 return 0
391 391
392 392
393 393 def map_groups(path):
394 394 """
395 395 Given a full path to a repository, create all nested groups that this
396 396 repo is inside. This function creates parent-child relationships between
397 397 groups and creates default perms for all new groups.
398 398
399 399 :param paths: full path to repository
400 400 """
401 401 sa = meta.Session()
402 402 groups = path.split(Repository.url_sep())
403 403 parent = None
404 404 group = None
405 405
406 406 # last element is repo in nested groups structure
407 407 groups = groups[:-1]
408 408 rgm = ReposGroupModel(sa)
409 409 for lvl, group_name in enumerate(groups):
410 410 group_name = '/'.join(groups[:lvl] + [group_name])
411 411 group = RepoGroup.get_by_group_name(group_name)
412 412 desc = '%s group' % group_name
413 413
414 414 # skip folders that are now removed repos
415 415 if REMOVED_REPO_PAT.match(group_name):
416 416 break
417 417
418 418 if group is None:
419 419 log.debug('creating group level: %s group_name: %s' % (lvl,
420 420 group_name))
421 421 group = RepoGroup(group_name, parent)
422 422 group.group_description = desc
423 423 sa.add(group)
424 424 rgm._create_default_perms(group)
425 425 sa.flush()
426 426 parent = group
427 427 return group
428 428
429 429
430 def repo2db_mapper(initial_repo_list, remove_obsolete=False):
430 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
431 install_git_hook=False):
431 432 """
432 433 maps all repos given in initial_repo_list, non existing repositories
433 434 are created, if remove_obsolete is True it also check for db entries
434 435 that are not in initial_repo_list and removes them.
435 436
436 437 :param initial_repo_list: list of repositories found by scanning methods
437 438 :param remove_obsolete: check for obsolete entries in database
439 :param install_git_hook: if this is True, also check and install githook
440 for a repo if missing
438 441 """
439 442 from rhodecode.model.repo import RepoModel
443 from rhodecode.model.scm import ScmModel
440 444 sa = meta.Session()
441 445 rm = RepoModel()
442 446 user = sa.query(User).filter(User.admin == True).first()
443 447 if user is None:
444 448 raise Exception('Missing administrative account !')
445 449 added = []
446 450
447 451 for name, repo in initial_repo_list.items():
448 452 group = map_groups(name)
449 if not rm.get_by_repo_name(name):
453 repo = rm.get_by_repo_name(name)
454 if not repo:
450 455 log.info('repository %s not found creating now' % name)
451 456 added.append(name)
452 457 desc = (repo.description
453 458 if repo.description != 'unknown'
454 459 else '%s repository' % name)
455 460 rm.create_repo(
456 461 repo_name=name,
457 462 repo_type=repo.alias,
458 463 description=desc,
459 464 repos_group=getattr(group, 'group_id', None),
460 465 owner=user,
461 466 just_db=True
462 467 )
468 elif install_git_hook:
469 if repo.repo_type == 'git':
470 ScmModel().install_git_hook(repo.scm_instance)
463 471 sa.commit()
464 472 removed = []
465 473 if remove_obsolete:
466 474 # remove from database those repositories that are not in the filesystem
467 475 for repo in sa.query(Repository).all():
468 476 if repo.repo_name not in initial_repo_list.keys():
469 477 log.debug("Removing non existing repository found in db %s" %
470 478 repo.repo_name)
471 removed.append(repo.repo_name)
472 sa.delete(repo)
473 sa.commit()
479 try:
480 sa.delete(repo)
481 sa.commit()
482 removed.append(repo.repo_name)
483 except:
484 #don't hold further removals on error
485 log.error(traceback.format_exc())
474 486
475 487 # clear cache keys
476 488 log.debug("Clearing cache keys now...")
477 489 CacheInvalidation.clear_cache()
478 490 sa.commit()
479 491 return added, removed
480 492
481 493
482 494 # set cache regions for beaker so celery can utilise it
483 495 def add_cache(settings):
484 496 cache_settings = {'regions': None}
485 497 for key in settings.keys():
486 498 for prefix in ['beaker.cache.', 'cache.']:
487 499 if key.startswith(prefix):
488 500 name = key.split(prefix)[1].strip()
489 501 cache_settings[name] = settings[key].strip()
490 502 if cache_settings['regions']:
491 503 for region in cache_settings['regions'].split(','):
492 504 region = region.strip()
493 505 region_settings = {}
494 506 for key, value in cache_settings.items():
495 507 if key.startswith(region):
496 508 region_settings[key.split('.')[1]] = value
497 509 region_settings['expire'] = int(region_settings.get('expire',
498 510 60))
499 511 region_settings.setdefault('lock_dir',
500 512 cache_settings.get('lock_dir'))
501 513 region_settings.setdefault('data_dir',
502 514 cache_settings.get('data_dir'))
503 515
504 516 if 'type' not in region_settings:
505 517 region_settings['type'] = cache_settings.get('type',
506 518 'memory')
507 519 beaker.cache.cache_regions[region] = region_settings
508 520
509 521
510 522 def load_rcextensions(root_path):
511 523 import rhodecode
512 524 from rhodecode.config import conf
513 525
514 526 path = os.path.join(root_path, 'rcextensions', '__init__.py')
515 527 if os.path.isfile(path):
516 528 rcext = create_module('rc', path)
517 529 EXT = rhodecode.EXTENSIONS = rcext
518 530 log.debug('Found rcextensions now loading %s...' % rcext)
519 531
520 532 # Additional mappings that are not present in the pygments lexers
521 533 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
522 534
523 535 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
524 536
525 537 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
526 538 log.debug('settings custom INDEX_EXTENSIONS')
527 539 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
528 540
529 541 #ADDITIONAL MAPPINGS
530 542 log.debug('adding extra into INDEX_EXTENSIONS')
531 543 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
532 544
533 545
534 546 #==============================================================================
535 547 # TEST FUNCTIONS AND CREATORS
536 548 #==============================================================================
537 549 def create_test_index(repo_location, config, full_index):
538 550 """
539 551 Makes default test index
540 552
541 553 :param config: test config
542 554 :param full_index:
543 555 """
544 556
545 557 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
546 558 from rhodecode.lib.pidlock import DaemonLock, LockHeld
547 559
548 560 repo_location = repo_location
549 561
550 562 index_location = os.path.join(config['app_conf']['index_dir'])
551 563 if not os.path.exists(index_location):
552 564 os.makedirs(index_location)
553 565
554 566 try:
555 567 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
556 568 WhooshIndexingDaemon(index_location=index_location,
557 569 repo_location=repo_location)\
558 570 .run(full_index=full_index)
559 571 l.release()
560 572 except LockHeld:
561 573 pass
562 574
563 575
564 576 def create_test_env(repos_test_path, config):
565 577 """
566 578 Makes a fresh database and
567 579 install test repository into tmp dir
568 580 """
569 581 from rhodecode.lib.db_manage import DbManage
570 582 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
571 583
572 584 # PART ONE create db
573 585 dbconf = config['sqlalchemy.db1.url']
574 586 log.debug('making test db %s' % dbconf)
575 587
576 588 # create test dir if it doesn't exist
577 589 if not os.path.isdir(repos_test_path):
578 590 log.debug('Creating testdir %s' % repos_test_path)
579 591 os.makedirs(repos_test_path)
580 592
581 593 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
582 594 tests=True)
583 595 dbmanage.create_tables(override=True)
584 596 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
585 597 dbmanage.create_default_user()
586 598 dbmanage.admin_prompt()
587 599 dbmanage.create_permissions()
588 600 dbmanage.populate_default_permissions()
589 601 Session().commit()
590 602 # PART TWO make test repo
591 603 log.debug('making test vcs repositories')
592 604
593 605 idx_path = config['app_conf']['index_dir']
594 606 data_path = config['app_conf']['cache_dir']
595 607
596 608 #clean index and data
597 609 if idx_path and os.path.exists(idx_path):
598 610 log.debug('remove %s' % idx_path)
599 611 shutil.rmtree(idx_path)
600 612
601 613 if data_path and os.path.exists(data_path):
602 614 log.debug('remove %s' % data_path)
603 615 shutil.rmtree(data_path)
604 616
605 617 #CREATE DEFAULT TEST REPOS
606 618 cur_dir = dn(dn(abspath(__file__)))
607 619 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
608 620 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
609 621 tar.close()
610 622
611 623 cur_dir = dn(dn(abspath(__file__)))
612 624 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
613 625 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
614 626 tar.close()
615 627
616 628 #LOAD VCS test stuff
617 629 from rhodecode.tests.vcs import setup_package
618 630 setup_package()
619 631
620 632
621 633 #==============================================================================
622 634 # PASTER COMMANDS
623 635 #==============================================================================
624 636 class BasePasterCommand(Command):
625 637 """
626 638 Abstract Base Class for paster commands.
627 639
628 640 The celery commands are somewhat aggressive about loading
629 641 celery.conf, and since our module sets the `CELERY_LOADER`
630 642 environment variable to our loader, we have to bootstrap a bit and
631 643 make sure we've had a chance to load the pylons config off of the
632 644 command line, otherwise everything fails.
633 645 """
634 646 min_args = 1
635 647 min_args_error = "Please provide a paster config file as an argument."
636 648 takes_config_file = 1
637 649 requires_config_file = True
638 650
639 651 def notify_msg(self, msg, log=False):
640 652 """Make a notification to user, additionally if logger is passed
641 653 it logs this action using given logger
642 654
643 655 :param msg: message that will be printed to user
644 656 :param log: logging instance, to use to additionally log this message
645 657
646 658 """
647 659 if log and isinstance(log, logging):
648 660 log(msg)
649 661
650 662 def run(self, args):
651 663 """
652 664 Overrides Command.run
653 665
654 666 Checks for a config file argument and loads it.
655 667 """
656 668 if len(args) < self.min_args:
657 669 raise BadCommand(
658 670 self.min_args_error % {'min_args': self.min_args,
659 671 'actual_args': len(args)})
660 672
661 673 # Decrement because we're going to lob off the first argument.
662 674 # @@ This is hacky
663 675 self.min_args -= 1
664 676 self.bootstrap_config(args[0])
665 677 self.update_parser()
666 678 return super(BasePasterCommand, self).run(args[1:])
667 679
668 680 def update_parser(self):
669 681 """
670 682 Abstract method. Allows for the class's parser to be updated
671 683 before the superclass's `run` method is called. Necessary to
672 684 allow options/arguments to be passed through to the underlying
673 685 celery command.
674 686 """
675 687 raise NotImplementedError("Abstract Method.")
676 688
677 689 def bootstrap_config(self, conf):
678 690 """
679 691 Loads the pylons configuration.
680 692 """
681 693 from pylons import config as pylonsconfig
682 694
683 695 self.path_to_ini_file = os.path.realpath(conf)
684 696 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
685 697 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
General Comments 0
You need to be logged in to leave comments. Login now