1 | """
|
---|
2 | django_extensions.management.jobs
|
---|
3 | """
|
---|
4 |
|
---|
5 | import os
|
---|
6 | from imp import find_module
|
---|
7 |
|
---|
8 | _jobs = None
|
---|
9 |
|
---|
10 | def noneimplementation(meth):
|
---|
11 | return None
|
---|
12 |
|
---|
13 | class JobError(Exception):
|
---|
14 | pass
|
---|
15 |
|
---|
16 | class BaseJob(object):
|
---|
17 | help = "undefined job description."
|
---|
18 | when = None
|
---|
19 |
|
---|
20 | def execute(self):
|
---|
21 | raise NotImplementedError("Job needs to implement the execute method")
|
---|
22 |
|
---|
23 | class HourlyJob(BaseJob):
|
---|
24 | when = "hourly"
|
---|
25 |
|
---|
26 | class DailyJob(BaseJob):
|
---|
27 | when = "daily"
|
---|
28 |
|
---|
29 | class WeeklyJob(BaseJob):
|
---|
30 | when = "weekly"
|
---|
31 |
|
---|
32 | class MonthlyJob(BaseJob):
|
---|
33 | when = "monthly"
|
---|
34 |
|
---|
35 | def my_import(name):
|
---|
36 | imp = __import__(name)
|
---|
37 | mods = name.split('.')
|
---|
38 | if len(mods)>1:
|
---|
39 | for mod in mods[1:]:
|
---|
40 | imp = getattr(imp, mod)
|
---|
41 | return imp
|
---|
42 |
|
---|
43 | def find_jobs(jobs_dir):
|
---|
44 | try:
|
---|
45 | return [f[:-3] for f in os.listdir(jobs_dir) \
|
---|
46 | if not f.startswith('_') and f.endswith(".py")]
|
---|
47 | except OSError:
|
---|
48 | return []
|
---|
49 |
|
---|
50 | def find_job_module(app_name, when=None):
|
---|
51 | parts = app_name.split('.')
|
---|
52 | parts.append('jobs')
|
---|
53 | if when:
|
---|
54 | parts.append(when)
|
---|
55 | parts.reverse()
|
---|
56 | path = None
|
---|
57 | while parts:
|
---|
58 | part = parts.pop()
|
---|
59 | f, path, descr = find_module(part, path and [path] or None)
|
---|
60 | return path
|
---|
61 |
|
---|
62 | def import_job(app_name, name, when=None):
|
---|
63 | jobmodule = "%s.jobs.%s%s" % (app_name, when and "%s." % when or "", name)
|
---|
64 | job_mod = my_import(jobmodule)
|
---|
65 | # todo: more friendly message for AttributeError if job_mod does not exist
|
---|
66 | try:
|
---|
67 | job = job_mod.Job
|
---|
68 | except:
|
---|
69 | raise JobError("Job module %s does not contain class instance named 'Job'" % jobmodule)
|
---|
70 | if when and not (job.when == when or job.when == None):
|
---|
71 | raise JobError("Job %s is not a %s job." % (jobmodule, when))
|
---|
72 | return job
|
---|
73 |
|
---|
74 | def get_jobs(when=None, only_scheduled=False):
|
---|
75 | """
|
---|
76 | Returns a dictionary mapping of job names together with there respective
|
---|
77 | application class.
|
---|
78 | """
|
---|
79 | global _jobs
|
---|
80 | # FIXME: HACK: make sure the project dir is on the path when executed as ./manage.py
|
---|
81 | import sys
|
---|
82 | try:
|
---|
83 | cpath = os.path.dirname(os.path.realpath(sys.argv[0]))
|
---|
84 | ppath = os.path.dirname(cpath)
|
---|
85 | if ppath not in sys.path:
|
---|
86 | sys.path.append(ppath)
|
---|
87 | except:
|
---|
88 | pass
|
---|
89 | if _jobs is None:
|
---|
90 | _jobs = {}
|
---|
91 | if True:
|
---|
92 | from django.conf import settings
|
---|
93 | for app_name in settings.INSTALLED_APPS:
|
---|
94 | scandirs = (None, 'hourly', 'daily', 'weekly', 'monthly')
|
---|
95 | if when:
|
---|
96 | scandirs = None, when
|
---|
97 | for subdir in scandirs:
|
---|
98 | try:
|
---|
99 | path = find_job_module(app_name, subdir)
|
---|
100 | for name in find_jobs(path):
|
---|
101 | if (app_name, name) in _jobs:
|
---|
102 | raise JobError("Duplicate job %s" % name)
|
---|
103 | job = import_job(app_name, name, subdir)
|
---|
104 | if only_scheduled and job.when == None:
|
---|
105 | # only include jobs which are scheduled
|
---|
106 | continue
|
---|
107 | if when and job.when != when:
|
---|
108 | # generic job not in same schedule
|
---|
109 | continue
|
---|
110 | _jobs[(app_name, name)] = job
|
---|
111 | except ImportError:
|
---|
112 | pass # No job module -- continue scanning
|
---|
113 | return _jobs
|
---|
114 |
|
---|
115 | def get_job(app_name, job_name):
|
---|
116 | jobs = get_jobs()
|
---|
117 | if app_name:
|
---|
118 | return jobs[(app_name, job_name)]
|
---|
119 | else:
|
---|
120 | for a, j in jobs.keys():
|
---|
121 | if j==job_name:
|
---|
122 | return jobs[(a, j)]
|
---|
123 | raise KeyError("Job not found: %s" % job_name)
|
---|
124 |
|
---|
125 | def print_jobs(when=None, only_scheduled=False, show_when=True, \
|
---|
126 | show_appname=False, show_header=True):
|
---|
127 | jobmap = get_jobs(when, only_scheduled=only_scheduled)
|
---|
128 | print "Job List: %i jobs" % len(jobmap)
|
---|
129 | jlist = jobmap.keys()
|
---|
130 | jlist.sort()
|
---|
131 | appname_spacer = "%%-%is" % max(len(e[0]) for e in jlist)
|
---|
132 | name_spacer = "%%-%is" % max(len(e[1]) for e in jlist)
|
---|
133 | when_spacer = "%%-%is" % max(len(e.when) for e in jobmap.values() if e.when)
|
---|
134 | if show_header:
|
---|
135 | line = " "
|
---|
136 | if show_appname:
|
---|
137 | line += appname_spacer % "appname" + " - "
|
---|
138 | line += name_spacer % "jobname"
|
---|
139 | if show_when:
|
---|
140 | line += " - " + when_spacer % "when"
|
---|
141 | line += " - help"
|
---|
142 | print line
|
---|
143 | print "-"*80
|
---|
144 |
|
---|
145 | for app_name, job_name in jlist:
|
---|
146 | job = jobmap[(app_name, job_name)]
|
---|
147 | line = " "
|
---|
148 | if show_appname:
|
---|
149 | line += appname_spacer % app_name + " - "
|
---|
150 | line += name_spacer % job_name
|
---|
151 | if show_when:
|
---|
152 | line += " - " + when_spacer % (job.when and job.when or "")
|
---|
153 | line += " - " + job.help
|
---|
154 | print line
|
---|