33from datetime import datetime
44from enum import Enum
55from pathlib import Path
6- from typing import Optional
6+
7+ # we use PurePosixPath as a convenient url path representation
8+ from pathlib import PurePosixPath as UrlPath
9+ from typing import Optional , Protocol
710
811from django .conf import settings
912from django .shortcuts import reverse
1215from airlock .users import User
1316
1417
18+ ROOT_PATH = UrlPath () # empty path
19+
20+
1521class Status (Enum ):
1622 """Status for release Requests"""
1723
@@ -25,27 +31,30 @@ class Status(Enum):
2531 RELEASED = "RELEASED"
2632
2733
28- class AirlockContainer :
29- """Abstract class for a directory or workspace or request files.
34+ class AirlockContainer ( Protocol ) :
35+ """Structural typing class for a instance of a Workspace or ReleaseRequest
3036
31- Provides a uniform interface for accessing information about this directory.
37+ Provides a uniform interface for accessing information about the paths and files
38+ contained within this instance.
3239 """
3340
34- def root (self ):
35- raise NotImplementedError ()
41+ # The currently selected path in this container. Used to calculate how
42+ # a particular path relates to it, i.e. if path *is* the currently selected
43+ # path, or is one of its parents.
44+ selected_path : UrlPath = ROOT_PATH
3645
37- def get_id (self ):
38- raise NotImplementedError ()
46+ def root (self ) -> Path :
47+ """Absolute concrete Path to root dir for files in this container."""
3948
40- def get_absolute_url (self ):
41- raise NotImplementedError ()
49+ def get_id (self ) -> str :
50+ """Get the human name for this container."""
4251
43- def get_url_for_path (self ) :
44- raise NotImplementedError ()
52+ def get_url (self , path : UrlPath = ROOT_PATH ) -> str :
53+ """Get the url for the container object with path"""
4554
4655
4756@dataclass
48- class Workspace ( AirlockContainer ) :
57+ class Workspace :
4958 """Simple wrapper around a workspace directory on disk.
5059
5160 Deliberately a dumb python object - the only operations are about accessing
@@ -54,6 +63,9 @@ class Workspace(AirlockContainer):
5463
5564 name : str
5665
66+ # can be set to mark the currently selected path in this workspace
67+ selected_path : UrlPath = ROOT_PATH
68+
5769 def __post_init__ (self ):
5870 if not self .root ().exists ():
5971 raise ProviderAPI .WorkspaceNotFound (self .name )
@@ -64,10 +76,7 @@ def root(self):
6476 def get_id (self ):
6577 return self .name
6678
67- def get_absolute_url (self ):
68- return reverse ("workspace_home" , kwargs = {"workspace_name" : self .name })
69-
70- def get_url_for_path (self , relpath ):
79+ def get_url (self , relpath = ROOT_PATH ):
7180 return reverse (
7281 "workspace_view" ,
7382 kwargs = {"workspace_name" : self .name , "path" : relpath },
@@ -99,7 +108,7 @@ class RequestFile:
99108 Represents a single file within a release request
100109 """
101110
102- relpath : Path
111+ relpath : UrlPath
103112
104113
105114@dataclass (frozen = True )
@@ -113,7 +122,7 @@ class FileGroup:
113122
114123
115124@dataclass
116- class ReleaseRequest ( AirlockContainer ) :
125+ class ReleaseRequest :
117126 """Represents a release request made by a user.
118127
119128 Deliberately a dumb python object. Does not operate on the state of request,
@@ -129,6 +138,9 @@ class ReleaseRequest(AirlockContainer):
129138 status : Status = Status .PENDING
130139 filegroups : dict [FileGroup ] = field (default_factory = dict )
131140
141+ # can be set to mark the currently selected path in this release request
142+ selected_path : UrlPath = ROOT_PATH
143+
132144 def __post_init__ (self ):
133145 self .root ().mkdir (parents = True , exist_ok = True )
134146
@@ -138,15 +150,7 @@ def root(self):
138150 def get_id (self ):
139151 return self .id
140152
141- def get_absolute_url (self ):
142- return reverse (
143- "request_home" ,
144- kwargs = {
145- "request_id" : self .id ,
146- },
147- )
148-
149- def get_url_for_path (self , relpath ):
153+ def get_url (self , relpath = ROOT_PATH ):
150154 return reverse (
151155 "request_view" ,
152156 kwargs = {
@@ -324,7 +328,7 @@ def set_status(
324328 def add_file_to_request (
325329 self ,
326330 release_request : ReleaseRequest ,
327- relpath : Path ,
331+ relpath : UrlPath ,
328332 user : User ,
329333 group_name : Optional [str ] = "default" ,
330334 ):
@@ -370,7 +374,7 @@ def release_files(self, request: ReleaseRequest, user: User):
370374 )
371375
372376 for f in filelist .files :
373- relpath = Path (f .name )
377+ relpath = UrlPath (f .name )
374378 old_api .upload_file (
375379 jobserver_release_id , relpath , request .root () / relpath , user .username
376380 )
0 commit comments