##// END OF EJS Templates
we must rollback if repo2db mapper cleanup fails ! Session blows up, and that code still throws an error without it
marcink -
r2635:d6fa7805 beta
parent child Browse files
Show More
@@ -1,702 +1,703 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 430 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
431 431 install_git_hook=False):
432 432 """
433 433 maps all repos given in initial_repo_list, non existing repositories
434 434 are created, if remove_obsolete is True it also check for db entries
435 435 that are not in initial_repo_list and removes them.
436 436
437 437 :param initial_repo_list: list of repositories found by scanning methods
438 438 :param remove_obsolete: check for obsolete entries in database
439 439 :param install_git_hook: if this is True, also check and install githook
440 440 for a repo if missing
441 441 """
442 442 from rhodecode.model.repo import RepoModel
443 443 from rhodecode.model.scm import ScmModel
444 444 sa = meta.Session()
445 445 rm = RepoModel()
446 446 user = sa.query(User).filter(User.admin == True).first()
447 447 if user is None:
448 448 raise Exception('Missing administrative account !')
449 449 added = []
450 450
451 451 for name, repo in initial_repo_list.items():
452 452 group = map_groups(name)
453 453 db_repo = rm.get_by_repo_name(name)
454 454 # found repo that is on filesystem not in RhodeCode database
455 455 if not db_repo:
456 456 log.info('repository %s not found creating now' % name)
457 457 added.append(name)
458 458 desc = (repo.description
459 459 if repo.description != 'unknown'
460 460 else '%s repository' % name)
461 461 new_repo = rm.create_repo(
462 462 repo_name=name,
463 463 repo_type=repo.alias,
464 464 description=desc,
465 465 repos_group=getattr(group, 'group_id', None),
466 466 owner=user,
467 467 just_db=True
468 468 )
469 469 # we added that repo just now, and make sure it has githook
470 470 # installed
471 471 if new_repo.repo_type == 'git':
472 472 ScmModel().install_git_hook(new_repo.scm_instance)
473 473 elif install_git_hook:
474 474 if db_repo.repo_type == 'git':
475 475 ScmModel().install_git_hook(db_repo.scm_instance)
476 476 sa.commit()
477 477 removed = []
478 478 if remove_obsolete:
479 479 # remove from database those repositories that are not in the filesystem
480 480 for repo in sa.query(Repository).all():
481 481 if repo.repo_name not in initial_repo_list.keys():
482 log.debug("Removing non existing repository found in db %s" %
482 log.debug("Removing non existing repository found in db `%s`" %
483 483 repo.repo_name)
484 484 try:
485 485 sa.delete(repo)
486 486 sa.commit()
487 487 removed.append(repo.repo_name)
488 488 except:
489 489 #don't hold further removals on error
490 490 log.error(traceback.format_exc())
491 sa.rollback()
491 492
492 493 # clear cache keys
493 494 log.debug("Clearing cache keys now...")
494 495 CacheInvalidation.clear_cache()
495 496 sa.commit()
496 497 return added, removed
497 498
498 499
499 500 # set cache regions for beaker so celery can utilise it
500 501 def add_cache(settings):
501 502 cache_settings = {'regions': None}
502 503 for key in settings.keys():
503 504 for prefix in ['beaker.cache.', 'cache.']:
504 505 if key.startswith(prefix):
505 506 name = key.split(prefix)[1].strip()
506 507 cache_settings[name] = settings[key].strip()
507 508 if cache_settings['regions']:
508 509 for region in cache_settings['regions'].split(','):
509 510 region = region.strip()
510 511 region_settings = {}
511 512 for key, value in cache_settings.items():
512 513 if key.startswith(region):
513 514 region_settings[key.split('.')[1]] = value
514 515 region_settings['expire'] = int(region_settings.get('expire',
515 516 60))
516 517 region_settings.setdefault('lock_dir',
517 518 cache_settings.get('lock_dir'))
518 519 region_settings.setdefault('data_dir',
519 520 cache_settings.get('data_dir'))
520 521
521 522 if 'type' not in region_settings:
522 523 region_settings['type'] = cache_settings.get('type',
523 524 'memory')
524 525 beaker.cache.cache_regions[region] = region_settings
525 526
526 527
527 528 def load_rcextensions(root_path):
528 529 import rhodecode
529 530 from rhodecode.config import conf
530 531
531 532 path = os.path.join(root_path, 'rcextensions', '__init__.py')
532 533 if os.path.isfile(path):
533 534 rcext = create_module('rc', path)
534 535 EXT = rhodecode.EXTENSIONS = rcext
535 536 log.debug('Found rcextensions now loading %s...' % rcext)
536 537
537 538 # Additional mappings that are not present in the pygments lexers
538 539 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
539 540
540 541 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
541 542
542 543 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
543 544 log.debug('settings custom INDEX_EXTENSIONS')
544 545 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
545 546
546 547 #ADDITIONAL MAPPINGS
547 548 log.debug('adding extra into INDEX_EXTENSIONS')
548 549 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
549 550
550 551
551 552 #==============================================================================
552 553 # TEST FUNCTIONS AND CREATORS
553 554 #==============================================================================
554 555 def create_test_index(repo_location, config, full_index):
555 556 """
556 557 Makes default test index
557 558
558 559 :param config: test config
559 560 :param full_index:
560 561 """
561 562
562 563 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
563 564 from rhodecode.lib.pidlock import DaemonLock, LockHeld
564 565
565 566 repo_location = repo_location
566 567
567 568 index_location = os.path.join(config['app_conf']['index_dir'])
568 569 if not os.path.exists(index_location):
569 570 os.makedirs(index_location)
570 571
571 572 try:
572 573 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
573 574 WhooshIndexingDaemon(index_location=index_location,
574 575 repo_location=repo_location)\
575 576 .run(full_index=full_index)
576 577 l.release()
577 578 except LockHeld:
578 579 pass
579 580
580 581
581 582 def create_test_env(repos_test_path, config):
582 583 """
583 584 Makes a fresh database and
584 585 install test repository into tmp dir
585 586 """
586 587 from rhodecode.lib.db_manage import DbManage
587 588 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
588 589
589 590 # PART ONE create db
590 591 dbconf = config['sqlalchemy.db1.url']
591 592 log.debug('making test db %s' % dbconf)
592 593
593 594 # create test dir if it doesn't exist
594 595 if not os.path.isdir(repos_test_path):
595 596 log.debug('Creating testdir %s' % repos_test_path)
596 597 os.makedirs(repos_test_path)
597 598
598 599 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
599 600 tests=True)
600 601 dbmanage.create_tables(override=True)
601 602 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
602 603 dbmanage.create_default_user()
603 604 dbmanage.admin_prompt()
604 605 dbmanage.create_permissions()
605 606 dbmanage.populate_default_permissions()
606 607 Session().commit()
607 608 # PART TWO make test repo
608 609 log.debug('making test vcs repositories')
609 610
610 611 idx_path = config['app_conf']['index_dir']
611 612 data_path = config['app_conf']['cache_dir']
612 613
613 614 #clean index and data
614 615 if idx_path and os.path.exists(idx_path):
615 616 log.debug('remove %s' % idx_path)
616 617 shutil.rmtree(idx_path)
617 618
618 619 if data_path and os.path.exists(data_path):
619 620 log.debug('remove %s' % data_path)
620 621 shutil.rmtree(data_path)
621 622
622 623 #CREATE DEFAULT TEST REPOS
623 624 cur_dir = dn(dn(abspath(__file__)))
624 625 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_hg.tar.gz"))
625 626 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
626 627 tar.close()
627 628
628 629 cur_dir = dn(dn(abspath(__file__)))
629 630 tar = tarfile.open(jn(cur_dir, 'tests', "vcs_test_git.tar.gz"))
630 631 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
631 632 tar.close()
632 633
633 634 #LOAD VCS test stuff
634 635 from rhodecode.tests.vcs import setup_package
635 636 setup_package()
636 637
637 638
638 639 #==============================================================================
639 640 # PASTER COMMANDS
640 641 #==============================================================================
641 642 class BasePasterCommand(Command):
642 643 """
643 644 Abstract Base Class for paster commands.
644 645
645 646 The celery commands are somewhat aggressive about loading
646 647 celery.conf, and since our module sets the `CELERY_LOADER`
647 648 environment variable to our loader, we have to bootstrap a bit and
648 649 make sure we've had a chance to load the pylons config off of the
649 650 command line, otherwise everything fails.
650 651 """
651 652 min_args = 1
652 653 min_args_error = "Please provide a paster config file as an argument."
653 654 takes_config_file = 1
654 655 requires_config_file = True
655 656
656 657 def notify_msg(self, msg, log=False):
657 658 """Make a notification to user, additionally if logger is passed
658 659 it logs this action using given logger
659 660
660 661 :param msg: message that will be printed to user
661 662 :param log: logging instance, to use to additionally log this message
662 663
663 664 """
664 665 if log and isinstance(log, logging):
665 666 log(msg)
666 667
667 668 def run(self, args):
668 669 """
669 670 Overrides Command.run
670 671
671 672 Checks for a config file argument and loads it.
672 673 """
673 674 if len(args) < self.min_args:
674 675 raise BadCommand(
675 676 self.min_args_error % {'min_args': self.min_args,
676 677 'actual_args': len(args)})
677 678
678 679 # Decrement because we're going to lob off the first argument.
679 680 # @@ This is hacky
680 681 self.min_args -= 1
681 682 self.bootstrap_config(args[0])
682 683 self.update_parser()
683 684 return super(BasePasterCommand, self).run(args[1:])
684 685
685 686 def update_parser(self):
686 687 """
687 688 Abstract method. Allows for the class's parser to be updated
688 689 before the superclass's `run` method is called. Necessary to
689 690 allow options/arguments to be passed through to the underlying
690 691 celery command.
691 692 """
692 693 raise NotImplementedError("Abstract Method.")
693 694
694 695 def bootstrap_config(self, conf):
695 696 """
696 697 Loads the pylons configuration.
697 698 """
698 699 from pylons import config as pylonsconfig
699 700
700 701 self.path_to_ini_file = os.path.realpath(conf)
701 702 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
702 703 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
General Comments 0
You need to be logged in to leave comments. Login now