Changeset 461
- Timestamp:
- 05/15/08 16:15:24 (8 months ago)
- Files:
-
- branches/trunk-pmd-intproto/server/storage.py (modified) (14 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/trunk-pmd-intproto/server/storage.py
r460 r461 188 188 self.logs_dir = os.path.join(self.root, '.__logs__') #logs are only kept at the root of the store 189 189 190 def add_file(self, name): 191 '''Add a single file to the store.''' 192 raise NotImplementedError 190 def add_file(self, name, e=None): 191 '''Add a single file to the store. Where name is the name of the file relative to path and e is its entry if it already exists.''' 192 now = int(time.time()) 193 storage_file = os.path.join(self.storage_dir, name + '.' + str(now)) 194 shutil.copy2(os.path.join(self.path, name), storage_file) 195 os.chmod(storage_file, os.stat(storage_file)[stat.ST_MODE] &~(stat.S_IWUSR|stat.S_IWGRP|stat.S_IWOTH)) 196 if e is None: 197 e = Entry(name) 198 e.initial = now 199 e.applied = now 200 e.latest = now 201 self.config.set('entries', name, pickle.dumps(e)) 202 return e 193 203 194 204 def remove_file(self, name): … … 196 206 raise NotImplementedError 197 207 198 def add_dir(self, name ):208 def add_dir(self, name, local=False): 199 209 '''Add a directory to the store. This function is not recursive.''' 200 raise NotImplementedError 210 e = Entry(name) 211 e.initial = now 212 e.applied = now 213 e.latest = now 214 if local: 215 e.type = 'LOCAL' 216 else: 217 if name == '.': 218 e.type = '.' 219 else: 220 e.type = 'DIR' 221 self.config.set('entries', name, pickle.dumps(e)) 222 return e 201 223 202 224 def remove_dir(self, name): … … 239 261 '''The Layer object maintains all data relevant to a single hierarchical group.''' 240 262 modified = False # set to True if the data in any field has changed since last sync to disk 241 name = '' # The name of a Layer is the relative path to the storage_root/.. 263 name = '' # The name of a Layer is the relative path to the storage_root/.. 242 264 description = '' # User configurable description of the type of files contained in the Layer 243 265 entries = {} # Dictionary of file name, Entry pairs per controlled file … … 253 275 for entry in self.storage.config.get_options('entries'): 254 276 self.entries[entry] = pickle.loads(self.storage.config.get('entries', entry)) 277 self.description = self.storage.config.get('general', 'description') 255 278 self.name = self.name[len(os.path.dirname(self.storage.root)) + 1:] #shorten name removing directories above root 256 279 … … 282 305 def export(self, dest_path): 283 306 '''Create a recursive copy of this Layer and the applied version of all its controlled files and subdirectories at dest_path without any revision control files.''' 284 raise NotImplementedError 307 if not os.path.exists(dest_path): 308 os.mkdir(dest_path) 309 if not os.path.is_dir(dest_path): 310 raise ValueError, '\'' + dest_path + '\' is not a directory.' 311 if not self.storage: 312 return #not controlled, nothing to export 313 for file in self.list_controlled_files(): 314 applied_file = self.get_current(file) 315 if applied_file: 316 dest_file = os.path.join(dest_path, os.path.basename(applied_file)) 317 shutil.copy2(applied_file, dest_file) 318 os.chmod(dest_file, os.stat(dest_file)[stat.ST_MODE]|stat.S_IWUSR) 319 for d in self.list_controlled_dirs(): 320 l = Layer(os.path.join(self.storage.path, d)) 321 l.export(os.path.join(dest_path, d)) 322 l.update() 285 323 286 324 def get_current(self, name): … … 295 333 return '' 296 334 cur = self.storage.find_recent(name, self.entries['.'].applied) 335 if cur == 0: 336 return '' 297 337 return os.path.join(self.storage.storage_dir, name) + '.' + str(cur) 298 338 … … 319 359 return True #deletion is a modification 320 360 statinfo = os.stat(path) 321 if statinfo.st_mtime > self.latest: 361 if statinfo.st_mtime > self.latest: 322 362 return True 323 363 return False … … 325 365 def checkin(self): 326 366 '''Recursively add new versions for all modified files.''' 327 raise NotImplementedError 367 if not self.storage: 368 raise RuntimeError, 'Directory \'' + self.name + '\' is not under revision control.' 369 for file in self.list_controlled_files(): 370 if self.is_modified(file) and not self.is_locked(file): 371 self.add(file) 372 for d in self.list_controlled_dirs(): 373 l = Layer(os.path.join(self.storage.path, d)) 374 l.checkin() 375 l.update() 328 376 329 377 #functions to add and remove files and directories … … 358 406 if e.lock: 359 407 raise RuntimeError, 'File \'' + name + '\' is locked; cannot add new version.' 360 if e.type == 'DIR': 361 408 if e.type == 'DIR' or e.type == 'LOCAL': 409 l = Layer(os.path.join(self.storage.path, name)) 410 l.add('.', recursive) 411 l.update() 412 return 413 else: #e.type=='FILE' 414 self.storage.add_file(name, e) 362 415 else: #no entry yet; create one 363 pass #TODO 364 raise NotImplementedError 416 path = os.path.join(self.storage.path, name) 417 if os.path.isdir(path): 418 e = self.storage.add_dir(name) 419 if recursive: 420 l = Layer(os.path.join(self.storage.path, name)) 421 l.add('.', recursive) 422 l.update() 423 else: 424 e = self.storage.add_file(name) 425 self.entries[name] = e 426 self.entries['.'].latest = e.latest 427 self.modified = True 365 428 366 429 def remove(self, names): … … 370 433 def control(self): 371 434 '''Place the layer under revision control; if already controlled, do nothing.''' 372 raise NotImplementedError 435 if self.storage: 436 return #already has control files. 437 self.storage = StorageData() 438 self.storage.path = self.name 439 self.storage.root = find_control_root(self.storage.path) 440 self.name = self.name[len(os.path.dirname(self.storage.root)) + 1:] #shorten name removing directories above root 441 self.storage.storage_dir = os.path.join(self.storage.path, '.__storage__') 442 os.mkdir(self.storage.storage_dir) 443 self.storage.nodes_dir = os.path.join(self.storage.path, '.__nodes__') 444 os.mkdir(self.storage.nodes_dir) 445 self.storage.logs_dir = os.path.join(self.storage.path, '__logs__') 446 if not os.path.exists(self.storage.logs_dir): 447 os.mkdir(self.storage.logs_dir) 448 self.storage.status_path = os.path.join(self.storage.path, '.__status__') 449 self.storage.config.add_section('general') 450 self.storage.config.set('general', 'description', self.description) 451 self.storage.config.set('general', 'root', self.storage.root) 452 self.storage.config.add_section('entries') 453 self.storage.add_dir('.') 454 self.storage.write() 455 if is_controlled(os.path.join(self.storage.path, '..')): 456 l = Layer(os.path.join(self.storage.path, '..')) 457 l.add(os.path.basename(self.storage.path)) 458 l.update() 373 459 374 460 def clean(self, names, recursive=False): … … 446 532 return ' ' + applied_stamp + latest_stamp 447 533 448 def status(self, name='.', recursive=False, prefix=''): 449 '''Return a string containing the status of name. If prefix is non-empty, prepend it to name in the returned string.''' 450 raise NotImplementedError 451 452 def revisions(self, name='.', recursive=False): 453 '''return a list of all versions of name.''' 454 raise NotImplementedError 534 def status(self, names='.', recursive=False, prefix=''): 535 '''Return a list of strings containing the status of name. If prefix is non-empty, prepend it to name in the returned string.''' 536 if names is None: 537 raise ValueError, 'Must specify a name.' 538 stats = [] 539 if names.__class__ == [].__class__: 540 for name in names: 541 stats += self.status(name, recursive, prefix) 542 return stats 543 if self.storage: 544 store_path = self.storage.path 545 else: 546 store_path = self.name 547 if os.path.basename(names) != names: 548 l = Layer(os.path.join(store_path, names)) 549 stats += l.status(os.path.basename(names), recursive, os.path.join(prefix, os.path.dirname(names))) 550 l.update() 551 return stats 552 elif names == '.': 553 stats.append(self.status_prefix(names) + prefix + self.name + self.version_suffix(names)) 554 if recursive: 555 for entry in os.listdir(store_path): 556 if entry in control_files: 557 continue 558 stats.append(self.status_path(entry) + entry + self.version_suffix(entry)) 559 return stats 560 e = self.get_entry(names) 561 if e: 562 stats.append(self.status_prefix(names) + prefix + names + self.version_suffix(names)) 563 if recursive and e.type != 'FILE': 564 l = Layer(os.path.join(self.storage.path, names) 565 stats += l.status('.', recursive) 566 l.update() 567 else: 568 stats.append(self.status_prefix(names) + prefix + names + self.version_suffix(names)) 569 return stats 570 571 def revisions(self, names='.', recursive=False): 572 '''Return a dictionary with a list of all versions of each named entry. Format is {(name,group):[<versions>]}''' 573 if names is None: 574 raise ValueError, 'Must specify a name.' 575 revs = {} 576 if names.__class__ == [].__class__: 577 for name in names: 578 nrev = self.revisions(name, recursive) 579 for i in nrev.keys(): 580 revs[i] = nrev[i] 581 return revs 582 if self.storage: 583 store_path = self.storage.path 584 else: 585 store_path = self.name 586 if names == '.': #everything in this dir 587 all_vers = set() 588 for file in list_controlled_files(): 589 nrev = self.storage.list_revisions(file) 590 if recursive: 591 revs[(file, self.name)] = nrev 592 all_vers += set(nrev) 593 revs[('.', self.name)] = list(all_vers) 594 if recursive and len(self.list_controlled_dirs()): 595 nrev = self.revisions(self.list_controlled_dirs(), recursive) 596 for i in nrev.keys(): 597 revs[i] = nrev[i] 598 return revs 599 elif os.path.is_dir(os.path.join(store_path, names)): # some other dir 600 l = Layer(os.path.join(store_path, names)) 601 revs = l.revisions('.', recursive) 602 l.update() 603 return revs 604 elif os.path.basename(names) != names: # file in another dir 605 l = Layer(os.path.join(store_path, names)) 606 revs = l.revisions(os.path.basename(names), recursive) 607 l.update() 608 return revs 609 elif not self.storage: #local file but . is not controlled 610 return {} 611 e = self.get_entry(names) 612 if not e: # local file not under control 613 return {} 614 return {(names, self.name):self.list_revisions(names)} 455 615 456 616 def list_controlled_files(self): 457 617 '''Return a list of all files under revision control in this Layer.''' 458 raise NotImplementedError 618 files = [] 619 for e in self.entries.keys(): 620 if self.entries[e].type == 'FILE': 621 files.append(e) 622 return files 459 623 460 624 def list_controlled_dirs(self): 461 625 '''Return a list of all controlled subdirectories under this Layer.''' 462 raise NotImplementedError 626 dirs = [] 627 for e in self.entries.keys(): 628 if self.entries[e] != 'FILES' and e != '.': 629 dirs.append(e) 630 return dirs 463 631 464 632 def list_controlled(self): … … 466 634 return self.list_controlled_files() + self.list_controlled_dirs() 467 635 468 def group_name(self):469 '''Return the group name this Layer represents; this is the name used by Nodes for classification.'''470 raise NotImplementedError471 472 636 #locking functions 473 637 def lock(self, names=['.'], recursive=False): … … 481 645 def is_locked(self, name='.', recursive=False): #add recursive as option) 482 646 '''Return True if name was locked by a prior call to lock(); if recursive, return True if any file under name is locked.''' 483 raise NotImplementedError 647 if not storage: 648 return False #not controlled, can't be locked 649 e = self.get_entry(name) 650 if not e: 651 return False #name is not controlled, can't be locked 652 if e.type == 'FILE': 653 return e.lock 654 elif name == '.': 655 if not recursive: 656 return e.lock 657 if e.lock: 658 return True 659 for file in self.list_controlled_files(): 660 if self.is_locked(file): 661 return True 662 for d in self.list_controlled_dirs(): 663 l = Layer(os.path.join(self.storage.path, d)) 664 if l.is_locked('.', True): 665 l.update() 666 return True 667 l.update() 668 else: 669 l = Layer(os.path.join(self.storage.path, name)) 670 if l.is_locked('.', True): 671 l.update() 672 return True 673 l.update() 674 return False 484 675 485 676 #node handling functions … … 505 696 def append_log_messages(self, id, messages): 506 697 '''Append log messages to the stored log cache for node id.''' 507 raise NotImplementedError 698 if not storage: 699 return False 700 if id not in self.list_nodes(): 701 self.add_node(id) 702 log_file = open(os.path.join(self.storage.logs_dir, id), 'a') 703 for message in messages: 704 pickle.dump(message, log_file) 705 log_file.close() 706 return True 508 707 509 708 def get_log_messages(self, id): 510 709 '''Retrieve all log messages stored for node id.''' 511 raise NotImplementedError 710 if not storage: 711 return [] 712 if id not in self.list_nodes(): 713 return [] 714 log_file = open(os.path.join(self.storage.logs_dir, id), 'r') 715 messages = pickle.load(log_file) 716 log_file.close() 717 return messages 512 718 513 719 #TODO should there be a clear log?
