~azzar1/unity/add-show-desktop-key

1165.3.48 by Matt Giuca
Added new script ivle-fetchsubmissions, which pulls submissions from students
1
#!/usr/bin/env python
2
# IVLE - Informatics Virtual Learning Environment
3
# Copyright (C) 2007-2009 The University of Melbourne
4
#
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
9
#
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19
# Program: Fetch Submissions
20
# Author:  Matt Giuca
21
22
# Script to retrieve all submissions for a particular project.
23
# Requires root to run.
24
25
import sys
26
import os
27
import datetime
28
import optparse
29
1165.3.53 by Matt Giuca
ivle-fetchsubmissions: Now actually svn exports the submissions to the target
30
import pysvn
31
1165.3.48 by Matt Giuca
Added new script ivle-fetchsubmissions, which pulls submissions from students
32
if os.getuid() != 0:
33
    print >>sys.stderr, "Must run %s as root." % os.path.basename(sys.argv[0])
34
    sys.exit()
35
36
import ivle.config
37
import ivle.database
38
39
from ivle.database import Project, ProjectSet, Offering, Subject
40
1165.3.53 by Matt Giuca
ivle-fetchsubmissions: Now actually svn exports the submissions to the target
41
def fetch_submission(submission, target, svnclient, config):
1165.3.48 by Matt Giuca
Added new script ivle-fetchsubmissions, which pulls submissions from students
42
    """Fetch a submission from a user's repository, and dump it in a given
43
    directory.
44
    @param submission: Submission object, detailing the submission.
45
    @param target: Target directory for the project (will create a
46
        subdirectory for each submission).
1165.3.49 by Matt Giuca
ivle.database.Assessed: Added property is_group.
47
    @param config: Config object.
1165.3.48 by Matt Giuca
Added new script ivle-fetchsubmissions, which pulls submissions from students
48
    """
49
    # submission_name is the name of the user or group who owns the repo
50
    submission_name = submission.assessed.principal.name
51
    # target_final is the directory to place the files in
52
    target_final = os.path.join(target, submission.assessed.principal.name)
53
    if not os.path.exists(target_final):
54
        os.makedirs(target_final)
1165.3.49 by Matt Giuca
ivle.database.Assessed: Added property is_group.
55
    url = get_repo_url(submission, config)
1165.3.53 by Matt Giuca
ivle-fetchsubmissions: Now actually svn exports the submissions to the target
56
    revision = pysvn.Revision(pysvn.opt_revision_kind.number,
57
                              submission.revision)
58
    svnclient.export(url, target_final, force=True,
59
        revision=revision, recurse=True)
1165.3.49 by Matt Giuca
ivle.database.Assessed: Added property is_group.
60
61
def get_repo_url(submission, config):
62
    """Gets a local (file:) URL to the repository for a given submission.
1165.3.50 by Matt Giuca
ivle-fetchsubmissions: Now gets the URL including the path within the
63
    This will consult submission.path to find the path within the repository
64
    to check out.
1165.3.49 by Matt Giuca
ivle.database.Assessed: Added property is_group.
65
    @param submission: Submission object, detailing the submission.
66
    @param config: Config object.
67
    """
68
    # NOTE: This code is mostly copied from services/usrmgt-server
69
    if submission.assessed.is_group:
70
        # The offering this group is in
71
        offering = submission.assessed.project.project_set.offering
72
        groupname = submission.assessed.principal.name
73
        # The name of the repository directory within 'groups' is
74
        # SUBJECT_YEAR_SEMESTER_GROUP
75
        namespace = "_".join([offering.subject.short_name,
76
            offering.semester.year, offering.semester.semester, groupname])
77
        repo_path = os.path.join(config['paths']['svn']['repo_path'],
78
                                'groups', namespace)
79
    else:
80
        # The name of the repository directory within 'users' is the username
81
        username = submission.assessed.principal.name
82
        repo_path = os.path.join(config['paths']['svn']['repo_path'],
83
                                'users', username)
84
1165.3.50 by Matt Giuca
ivle-fetchsubmissions: Now gets the URL including the path within the
85
    path_in_repo = submission.path
86
    # Change an absolute path into a relative one (to the top of SVN)
87
    if path_in_repo[:1] == os.sep or path_in_repo[:1] == os.altsep:
88
        path_in_repo = path_in_repo[1:]
89
1165.3.49 by Matt Giuca
ivle.database.Assessed: Added property is_group.
90
    # Attach "file://" to the front of the absolute path, to make it a URL
1165.3.50 by Matt Giuca
ivle-fetchsubmissions: Now gets the URL including the path within the
91
    return "file://" + os.path.join(os.path.abspath(repo_path), path_in_repo)
1165.3.48 by Matt Giuca
Added new script ivle-fetchsubmissions, which pulls submissions from students
92
93
def main(argv=None):
94
    global store
95
    if argv is None:
96
        argv = sys.argv
97
98
    usage = """usage: %prog [options] subject projname
99
    (requires root)
100
    Retrieves all submissions for a given project.
101
    projname is the project's short name."""
102
103
    # Parse arguments
104
    parser = optparse.OptionParser(usage)
105
    parser.add_option("-s", "--semester",
106
        action="store", dest="semester", metavar="YEAR/SEMESTER",
107
        help="Semester of the subject's offering (eg. 2009/1). "
108
             "Defaults to the currently active semester.",
109
        default=None)
110
    parser.add_option("-c", "--cutoff",
111
        action="store", dest="cutoff", metavar="DATE",
112
        help="Cutoff date (retrieve the submissions as of this date)."
113
             "YYYY-MM-DD H:M:S.",
114
        default=None)
115
    parser.add_option("-d", "--dest",
116
        action="store", dest="dest", metavar="PATH",
117
        help="Destination directory (default to '.', creates a subdirectory, "
118
            "so will not pollute PATH).",
119
        default=".")
120
    (options, args) = parser.parse_args(argv[1:])
121
122
    if len(args) < 2:
123
        parser.print_help()
124
        parser.exit()
125
126
    subject_name = unicode(args[0])
127
    project_name = unicode(args[1])
128
129
    if options.semester is None:
130
        year, semester = None, None
131
    else:
132
        try:
133
            year, semester = options.semester.split('/')
134
            if len(year) == 0 or len(semester) == 0:
135
                raise ValueError()
136
        except ValueError:
137
            parser.error('Invalid semester (must have form "year/semester")')
138
139
    if options.cutoff is not None:
140
        try:
141
            cutoff = datetime.datetime.strptime(options.cutoff,
142
                                                "%Y-%m-%d %H:%M:%S")
143
        except ValueError:
144
            parser.error("Invalid date format: '%s' "
145
                         "(must be YYYY-MM-DD H:M:S)." % options.cutoff)
146
    else:
147
        cutoff = None
148
1165.3.53 by Matt Giuca
ivle-fetchsubmissions: Now actually svn exports the submissions to the target
149
    svnclient = pysvn.Client()
1165.3.49 by Matt Giuca
ivle.database.Assessed: Added property is_group.
150
    config = ivle.config.Config(plugins=False)
151
    store = ivle.database.get_store(config)
1165.3.48 by Matt Giuca
Added new script ivle-fetchsubmissions, which pulls submissions from students
152
153
    # Get the subject from the DB
154
    subject = store.find(Subject,
155
                     Subject.short_name == subject_name).one()
156
    if subject is None:
157
        print >>sys.stderr, "No subject with short name '%s'" % subject_name
158
        return 1
159
160
    # Get the offering from the DB
161
    if semester is None:
162
        # None specified - get the current offering from the DB
163
        offerings = list(subject.active_offerings())
164
        if len(offerings) == 0:
165
            print >>sys.stderr, ("No active offering for subject '%s'"
166
                                 % subject_name)
167
            return 1
168
        elif len(offerings) > 1:
169
            print >>sys.stderr, ("Multiple active offerings for subject '%s':"
170
                                 % subject_name)
171
            print >>sys.stderr, "Please use one of:"
172
            for offering in offerings:
173
                print >>sys.stderr, ("    --semester=%s/%s"
174
                    % (offering.semester.year, offering.semester.semester))
175
            return 1
176
        else:
177
            offering = offerings[0]
178
    else:
179
        # Get the offering for the specified semester
180
        offering = subject.offering_for_semester(year, semester)
181
        if offering is None:
182
            print >>sys.stderr, (
183
                "No offering for subject '%s' in semester %s/%s"
184
                % (subject_name, year, semester))
185
            return 1
186
187
    # Get the project from the DB
188
    project = store.find(Project,
189
                         Project.project_set_id == ProjectSet.id,
190
                         ProjectSet.offering == offering,
191
                         Project.short_name == project_name).one()
192
    if project is None:
193
        print >>sys.stderr, "No project with short name '%s'" % project_name
194
        return 1
195
196
    # Target directory is DEST/subject/year/semester/project
197
    target_dir = os.path.join(options.dest, subject_name,
198
        offering.semester.year, offering.semester.semester, project_name)
199
    if not os.path.exists(target_dir):
200
        os.makedirs(target_dir)
201
202
    for submission in project.latest_submissions:
1165.3.53 by Matt Giuca
ivle-fetchsubmissions: Now actually svn exports the submissions to the target
203
        fetch_submission(submission, target_dir, svnclient, config)
1165.3.48 by Matt Giuca
Added new script ivle-fetchsubmissions, which pulls submissions from students
204
205
if __name__ == "__main__":
206
    sys.exit(main(sys.argv))