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

« back to all changes in this revision

Viewing changes to ivle/fileservice_lib/action.py

  • Committer: William Grant
  • Date: 2009-03-26 08:36:00 UTC
  • mto: (1165.3.1 submissions)
  • mto: This revision was merged to the branch mainline in revision 1174.
  • Revision ID: grantw@unimelb.edu.au-20090326083600-0nywchy08dzi0us1
Add an initial project selection UI to SubmitView.

Show diffs side-by-side

added added

removed removed

Lines of Context:
91
91
# action=svnupdate: Bring a file up to date with the head revision.
92
92
#       path:   The path to the file to be updated. Only one file may be
93
93
#               specified.
94
 
#       revision: The revision number to update to. If not provided this
95
 
#               defaults to HEAD.
 
94
#
 
95
# action=svnpublish: Set the "published" flag on a file to True.
 
96
#       path:   The path to the file to be published. Can be specified
 
97
#               multiple times.
 
98
#
 
99
# action=svnunpublish: Set the "published" flag on a file to False.
 
100
#       path:   The path to the file to be unpublished. Can be specified
 
101
#               multiple times.
96
102
#
97
103
# action=svncommit: Commit a file(s) or directory(s) to the repository.
98
104
#       path:   The path to the file or directory to be committed. Can be
113
119
#       path:   The path to the directory to be checked (under the IVLE
114
120
#               repository base).
115
121
#
116
 
# action=svncleanup: Recursively clean up the working copy, removing locks,
117
 
#   resuming unfinished operations, etc.
118
 
#       path:   The path to the directory to be cleaned
119
 
#
120
122
# TODO: Implement the following actions:
121
123
#   svnupdate (done?)
122
124
# TODO: Implement ZIP unpacking in putfiles (done?).
129
131
import os
130
132
import cStringIO
131
133
import shutil
132
 
import urllib
133
134
 
134
135
import pysvn
135
136
 
136
137
from ivle import (util, studpath, zip)
137
138
from ivle.fileservice_lib.exceptions import WillNotOverwrite
138
139
import ivle.conf
139
 
import ivle.svn
140
 
 
141
 
# Make a Subversion client object (which will log in with this user's
142
 
# credentials, upon request)
143
 
svnclient = ivle.svn.create_auth_svn_client(username=ivle.conf.login,
144
 
                                            password=ivle.conf.svn_pass)
 
140
 
 
141
 
 
142
def get_login(_realm, existing_login, _may_save):
 
143
    """Callback function used by pysvn for authentication.
 
144
    realm, existing_login, _may_save: The 3 arguments passed by pysvn to
 
145
        callback_get_login.
 
146
        The following has been determined empirically, not from docs:
 
147
        existing_login will be the name of the user who owns the process on
 
148
        the first attempt, "" on subsequent attempts. We use this fact.
 
149
    """
 
150
    # Only provide credentials on the _first_ attempt.
 
151
    # If we're being asked again, then it means the credentials failed for
 
152
    # some reason and we should just fail. (This is not desirable, but it's
 
153
    # better than being asked an infinite number of times).
 
154
    return (existing_login != "", str(ivle.conf.login),
 
155
                                  str(ivle.conf.svn_pass), True)
 
156
 
 
157
# Make a Subversion client object
 
158
svnclient = pysvn.Client()
 
159
svnclient.callback_get_login = get_login
145
160
svnclient.exception_style = 0               # Simple (string) exceptions
146
161
 
147
162
DEFAULT_LOGMESSAGE = "No log message supplied."
182
197
    except KeyError:
183
198
        # Default, just send an error but then continue
184
199
        raise ActionError("Unknown action")
185
 
    return action(req, fields)
 
200
    action(req, fields)
186
201
 
187
202
def actionpath_to_urlpath(req, path):
188
203
    """Determines the URL path (relative to the student home) upon which the
213
228
 
214
229
    Does not mutate req.
215
230
    """
216
 
    r = studpath.to_home_path(actionpath_to_urlpath(req, path))
 
231
    (_, _, r) = studpath.url_to_jailpaths(actionpath_to_urlpath(req, path))
217
232
    if r is None:
218
233
        raise ActionError("Invalid path")
219
234
    return r
405
420
    for datum in data:
406
421
        # Each of the uploaded files
407
422
        filepath = os.path.join(path, datum.filename)
408
 
        filepath_local = studpath.to_home_path(filepath)
 
423
        (_, _, filepath_local) = studpath.url_to_jailpaths(filepath)
409
424
        if os.path.isdir(filepath_local):
410
425
            raise ActionError("A directory already exists "
411
426
                    + "with that name")
421
436
            # filename)
422
437
            try:
423
438
                # First get the entire path (within jail)
424
 
                abspath = studpath.to_home_path(path)
 
439
                _, _, abspath = studpath.url_to_jailpaths(path)
425
440
                abspath = os.path.join(os.sep, abspath)
426
441
                zip.unzip(abspath, filedata)
427
442
            except (OSError, IOError):
430
445
                raise ActionError("File '" + e.filename + "' already exists.")
431
446
        else:
432
447
            # Not a zip file
433
 
            filepath_local = studpath.to_home_path(filepath)
 
448
            (_, _, filepath_local) = studpath.url_to_jailpaths(filepath)
434
449
            if filepath_local is None:
435
450
                raise ActionError("Invalid path")
436
451
 
517
532
    Reads fields: 'path'
518
533
    """
519
534
    paths = fields.getlist('path')
520
 
    user = util.split_path(req.path)[0]
 
535
    user = studpath.url_to_local(req.path)[0]
521
536
    homedir = "/home/%s" % user
522
537
    if len(paths):
523
538
        paths = map(lambda path: actionpath_to_local(req, path), paths)
524
539
    else:
525
 
        paths = [studpath.to_home_path(req.path)]
 
540
        paths = [studpath.url_to_jailpaths(req.path)[2]]
526
541
 
527
542
    # Set all the dirs in home dir world browsable (o+r,o+x)
528
543
    #FIXME: Should really only do those in the direct path not all of the 
552
567
    if len(paths):
553
568
        paths = map(lambda path: actionpath_to_local(req, path), paths)
554
569
    else:
555
 
        paths = [studpath.to_home_path(req.path)]
 
570
        paths = [studpath.url_to_jailpaths(req.path)[2]]
556
571
 
557
572
    try:
558
573
        for path in paths:
572
587
    Reads fields: 'path' (multiple)
573
588
    """
574
589
    paths = fields.getlist('path')
575
 
    paths = map(lambda path: actionpath_to_local(req, path).decode('utf-8'),
576
 
                paths)
 
590
    paths = map(lambda path: actionpath_to_local(req, path), paths)
577
591
 
578
592
    try:
579
593
        svnclient.add(paths, recurse=True, force=True)
586
600
    Reads fields: 'path' (multiple)
587
601
    """
588
602
    paths = fields.getlist('path')
589
 
    paths = map(lambda path: actionpath_to_local(req, path).decode('utf-8'),
590
 
                paths)
 
603
    paths = map(lambda path: actionpath_to_local(req, path), paths)
591
604
 
592
605
    try:
593
606
        svnclient.remove(paths, force=True)
597
610
def action_svnupdate(req, fields):
598
611
    """Performs a "svn update" to each file specified.
599
612
 
600
 
    Reads fields: 'path' and 'revision'
 
613
    Reads fields: 'path'
601
614
    """
602
615
    path = fields.getfirst('path')
603
 
    revision = fields.getfirst('revision')
604
616
    if path is None:
605
617
        raise ActionError("Required field missing")
606
 
    if revision is None:
607
 
        revision = pysvn.Revision( pysvn.opt_revision_kind.head )
608
 
    else:
609
 
        try:
610
 
            revision = pysvn.Revision(pysvn.opt_revision_kind.number,
611
 
                    int(revision))
612
 
        except ValueError, e:
613
 
            raise ActionError("Bad revision number: '%s'"%revision,)
614
 
    path = actionpath_to_local(req, path).decode('utf-8')
 
618
    path = actionpath_to_local(req, path)
615
619
 
616
620
    try:
617
 
        svnclient.update(path, recurse=True, revision=revision)
 
621
        svnclient.update(path, recurse=True)
618
622
    except pysvn.ClientError, e:
619
623
        raise ActionError(str(e))
620
624
 
626
630
    path = fields.getfirst('path')
627
631
    if path is None:
628
632
        raise ActionError("Required field missing")
629
 
    path = actionpath_to_local(req, path).decode('utf-8')
 
633
    path = actionpath_to_local(req, path)
630
634
 
631
635
    try:
632
636
        svnclient.resolved(path, recurse=True)
639
643
    Reads fields: 'path' (multiple)
640
644
    """
641
645
    paths = fields.getlist('path')
642
 
    paths = map(lambda path: actionpath_to_local(req, path).decode('utf-8'),
643
 
                paths)
 
646
    paths = map(lambda path: actionpath_to_local(req, path), paths)
644
647
 
645
648
    try:
646
649
        svnclient.revert(paths, recurse=True)
647
650
    except pysvn.ClientError, e:
648
651
        raise ActionError(str(e))
649
652
 
 
653
def action_svnpublish(req, fields):
 
654
    """Sets svn property "ivle:published" on each file specified.
 
655
    Should only be called on directories (only effective on directories
 
656
    anyway).
 
657
 
 
658
    Reads fields: 'path'
 
659
 
 
660
    XXX Currently unused by the client (calls action_publish instead, which
 
661
    has a completely different publishing model).
 
662
    """
 
663
    paths = fields.getlist('path')
 
664
    if len(paths):
 
665
        paths = map(lambda path: actionpath_to_local(req, path), paths)
 
666
    else:
 
667
        paths = [studpath.url_to_jailpaths(req.path)[2]]
 
668
 
 
669
    try:
 
670
        for path in paths:
 
671
            # Note: Property value doesn't matter
 
672
            svnclient.propset("ivle:published", "", path, recurse=False)
 
673
    except pysvn.ClientError, e:
 
674
        raise ActionError("Directory could not be published")
 
675
 
 
676
def action_svnunpublish(req, fields):
 
677
    """Deletes svn property "ivle:published" on each file specified.
 
678
 
 
679
    Reads fields: 'path'
 
680
 
 
681
    XXX Currently unused by the client (calls action_unpublish instead, which
 
682
    has a completely different publishing model).
 
683
    """
 
684
    paths = fields.getlist('path')
 
685
    paths = map(lambda path: actionpath_to_local(req, path), paths)
 
686
 
 
687
    try:
 
688
        for path in paths:
 
689
            svnclient.propdel("ivle:published", path, recurse=False)
 
690
    except pysvn.ClientError, e:
 
691
        raise ActionError("Directory could not be unpublished")
 
692
 
650
693
def action_svncommit(req, fields):
651
694
    """Performs a "svn commit" to each file specified.
652
695
 
653
696
    Reads fields: 'path' (multiple), 'logmsg' (optional)
654
697
    """
655
698
    paths = fields.getlist('path')
656
 
    if len(paths):
657
 
        paths = map(lambda path:actionpath_to_local(req,path).decode('utf-8'),
658
 
                    paths)
659
 
    else:
660
 
        paths = [studpath.to_home_path(req.path).decode('utf-8')]
661
 
    logmsg = str(fields.getfirst('logmsg',
662
 
                 DEFAULT_LOGMESSAGE)).decode('utf-8')
 
699
    paths = map(lambda path: actionpath_to_local(req, str(path)), paths)
 
700
    logmsg = str(fields.getfirst('logmsg', DEFAULT_LOGMESSAGE))
663
701
    if logmsg == '': logmsg = DEFAULT_LOGMESSAGE
664
702
 
665
703
    try:
675
713
    paths = fields.getlist('path')
676
714
    if len(paths) != 2:
677
715
        raise ActionError("usage: svncheckout url local-path")
678
 
    url = ivle.conf.svn_addr + "/" + urllib.quote(paths[0])
 
716
    url = ivle.conf.svn_addr + "/" + paths[0]
679
717
    local_path = actionpath_to_local(req, str(paths[1]))
680
 
    url = url.decode('utf-8')
681
 
    local_path = local_path.decode('utf-8')
682
718
    try:
 
719
        svnclient.callback_get_login = get_login
683
720
        svnclient.checkout(url, local_path, recurse=True)
684
721
    except pysvn.ClientError, e:
685
722
        raise ActionError(str(e))
691
728
    """
692
729
    path = fields.getfirst('path')
693
730
    logmsg = fields.getfirst('logmsg')
694
 
    url = (ivle.conf.svn_addr + "/" + urllib.quote(path)).decode('utf-8')
 
731
    url = ivle.conf.svn_addr + "/" + path
695
732
    try:
 
733
        svnclient.callback_get_login = get_login
696
734
        svnclient.mkdir(url, log_message=logmsg)
697
735
    except pysvn.ClientError, e:
698
736
        raise ActionError(str(e))
700
738
def action_svnrepostat(req, fields):
701
739
    """Discovers whether a path exists in a repo under the IVLE SVN root.
702
740
 
703
 
    If it does exist, returns a dict containing its metadata.
704
 
 
705
741
    Reads fields: 'path'
706
742
    """
707
743
    path = fields.getfirst('path')
708
 
    url = (ivle.conf.svn_addr + "/" + urllib.quote(path)).decode('utf-8')
709
 
    svnclient.exception_style = 1
 
744
    url = ivle.conf.svn_addr + "/" + path
 
745
    svnclient.exception_style = 1 
710
746
 
711
747
    try:
712
 
        info = svnclient.info2(url,
713
 
            revision=pysvn.Revision(pysvn.opt_revision_kind.head))[0][1]
714
 
        return {'svnrevision': info['rev'].number
715
 
                  if info['rev'] and
716
 
                     info['rev'].kind == pysvn.opt_revision_kind.number
717
 
                  else None}
 
748
        svnclient.callback_get_login = get_login
 
749
        svnclient.info2(url)
718
750
    except pysvn.ClientError, e:
719
751
        # Error code 170000 means ENOENT in this revision.
720
752
        if e[1][0][1] == 170000:
721
753
            raise util.IVLEError(404, 'The specified repository path does not exist')
722
754
        else:
723
755
            raise ActionError(str(e[0]))
724
 
 
725
 
 
726
 
def action_svncleanup(req, fields):
727
 
    """Recursively clean up the working copy, removing locks, resuming 
728
 
    unfinished operations, etc.
729
 
        path:   The path to be cleaned"""
730
 
 
731
 
    path = fields.getfirst('path')
732
 
    if path is None:
733
 
        raise ActionError("Required field missing")
734
 
    path = actionpath_to_local(req, path).decode('utf-8')
735
 
 
736
 
    try:
737
 
        svnclient.cleanup(path)
738
 
    except pysvn.ClientError, e:
739
 
        raise ActionError(str(e))
740
 
 
 
756
            
741
757
 
742
758
# Table of all action functions #
743
759
# Each function has the interface f(req, fields).
757
773
    "svnupdate" : action_svnupdate,
758
774
    "svnresolved" : action_svnresolved,
759
775
    "svnrevert" : action_svnrevert,
 
776
    "svnpublish" : action_svnpublish,
 
777
    "svnunpublish" : action_svnunpublish,
760
778
    "svncommit" : action_svncommit,
761
779
    "svncheckout" : action_svncheckout,
762
780
    "svnrepomkdir" : action_svnrepomkdir,
763
781
    "svnrepostat" : action_svnrepostat,
764
 
    "svncleanup" : action_svncleanup,
765
782
}