def run(self, args): if args.repository: repository_folder = File(args.repository) else: repository_folder = detect_repository(File()) if not repository_folder: raise Exception("You're not in a repository (or a working " "folder) right now and you didn't specify " "--repository.") if args.working: working_file = File(args.working) else: working_file = detect_working(silent=True) repository = Repository(repository_folder) revisions = None if working_file and working_file.has_xattr(XATTR_BASE) and not args.all: # We have a working file and we're not displaying all revisions. # Only show revisions which are ancestors of the working file. # TODO: Figure out a way to do this without having to reconstruct # every revision; probably need to have some sort of cache in the # Repository class of parent-child revision relationships. Still # thinking a Neo4j database might be useful for this, or maybe some # sort of equivalent SQLite database. revisions = set() base = json.loads(working_file.get_xattr(XATTR_BASE)) current = set(base) while current: # Find the revision with the highest number in current max_hash = max(current, key=lambda r: int(repository.number_for_rev(r))) revisions.add(max_hash) current.remove(max_hash) current |= set(repository.get_revision(max_hash)["parents"]) print for number, hash, data in repository.revision_iterator(): if revisions is not None and hash not in revisions: continue print u"Revision %s:%s:" % (number, hash) print u" date: %s" % time.ctime(data.get("info", {}).get("date", 0)) print u" type: %s" % data["type"] if data.get("current_name"): print u" committed as: %s" % data["current_name"] for cparent in data["parents"]: print u" change parent: %s:%s" % (repository.number_for_rev(cparent), cparent) # for dparent in repository.get_dirparents(hash): # print " dir parent: %s:%s" % (repository.number_for_rev(dparent), dparent) try: print u" message: %s" % data.get("info", {}).get("message", "") except: print >>sys.stderr, data raise print
def run(self, args): # The checkout command does something different depending on how it's # run: # # If the working copy (specified with --working or auto-detected) # exists and -r is specified, the working copy is updated to the # revision in question. # If the working copy exists but is not a working copy, it is turned # into one. Then, if -r is specified, it is updated to the specified # revision. # If the working copy does not exist, -r must be specified (so that we # know whether to create a file or a folder), and the working copy # will be created and updated to the revision in question. # # So, if the working copy does not exist, we require -r and create it. # Then, if it's not a working copy, we make it one by setting # XATTR_REPO. Then we go update the working copy to the specified # revision. if args.repository: repository_folder = File(args.repository) else: repository_folder = detect_repository() repository = Repository(repository_folder) if args.working: working_file = File(args.working) else: working_file = detect_working() revision = args.revision # Check to see if the soon-to-be working copy already exists as a file # or folder if not working_file.exists: # It doesn't exist. Make sure we've got a --revision (and error out # if we don't, since then we don't know whether to create a file or # a folder). if revision is None: raise Exception("When using the checkout command on a working " "copy that doesn't actually exist yet, --revision must " "be specified. This is because Filer doesn't know " "whether to create a folder or a file for it. If you " "want to create a new, blank working copy without " "checking one out from a revision, create a file or " "folder at the relevant location, then use the " "checkout command again. Then it'll work.") # We've got a revision, so look at whether it's a file or a folder, # and create a file or a folder accordingly. working_type = repository.get_revision(revision)["type"] if working_type == "file": # It's a file, so create a blank file for it. working_file.write("") else: # It's a folder, so create a blank folder for it. working_file.mkdir() # The working file exists. Now see if it's a working copy. working = WorkingCopy(repository, working_file) if not working.is_working(): # It's not a working copy, so make it a working copy. working.create() # Now update it. TODO: We might want to keep track of whether it # already existed before now, and if it did, warn the user that they'll # be overwriting their changes. if revision: if working_file.has_xattr(XATTR_BASE): base = json.loads(working_file.get_xattr(XATTR_BASE)) else: base = None # If we're already checked out, warn if we have multiple parents # as that'll likely steamroller over an impending merge. TODO: # might want to recursively walk down and make sure we don't have # any children that also have impending merges. if base and len(base) > 1: if not args.quiet and raw_input("The working copy has multiple parents; this " "usually means a merge is in progress. Do you still " "want to check out a new revision and overwrite " "your changes (y or n)? ").lower()[0] != "y": print "Stopping." return # If we're checked out with one parent, see if the new revision is # an ancestor of the current revision or vice versa. If not, warn # that we're jumping history lines. TODO: Don't warn if they're on # the same changeline, even if they're on disjointed branches of # the changeline. elif base and len(base) == 1: base_rev = base[0] new_rev = repository.rev_for_number(revision) if not (repository.is_ancestor(base_rev, new_rev) or repository.is_ancestor(new_rev, base_rev)): if not args.quiet and raw_input("The revision you're updating to (%s) is not " "an ancestor or a descendant of the working " "copy's current revision (%s). Do you still want " "to continue updating (y or n)? " % (new_rev, base_rev)).lower()[0] != "y": print "Stopping." return working.update_to(revision) print "Checked out revision %r" % revision else: print "Resetting working copy to untracked" delete_tracked(working_file)