def exists_ref(self, commit_id): """Returns a boolean if the commit exists Parameters ---------- commit_id : str commit id to check for Returns ------- bool True if exists else False Raises ------ CodeNotInitialized error if not initialized (must initialize first) """ if not self.is_initialized: raise CodeNotInitialized() # List all files in code directory commit_hashes = self.list_refs() # Check if commit_id exists in the list if commit_id in commit_hashes: return True return False
def latest_ref(self): """Returns the latest ref of the code Raises ------ CodeNotInitialized error if not initialized (must initialize first) """ if not self.is_initialized: raise CodeNotInitialized() def getmtime(absolute_filepath): # Keeping it granular as timestaps in git return int(os.path.getmtime(absolute_filepath)) # List all files in the code directory (ignore directories) for _, _, commit_hashes in os.walk(self._code_filepath): sorted_commit_hashes = sorted([ os.path.join(self._code_filepath, commit_hash) for commit_hash in commit_hashes ], key=getmtime, reverse=True) _, filename = os.path.split(sorted_commit_hashes[0]) return filename
def list_refs(self): """List all commits in repo Raises ------ CodeNotInitialized error if not initialized (must initialize first) """ if not self.is_initialized: raise CodeNotInitialized() # List all files in the code directory (ignore directories) for _, _, commit_hashes in os.walk(self._code_filepath): return commit_hashes
def delete_ref(self, commit_id): """Removes the commit hash file, but not the file references Raises ------ CodeNotInitialized error if not initialized (must initialize first) """ if not self.is_initialized: raise CodeNotInitialized() if not self.exists_ref(commit_id): raise FileIOError( __("error", "controller.code.driver.file.delete_ref")) commit_filepath = os.path.join(self._code_filepath, commit_id) os.remove(commit_filepath) return True
def current_ref(self): """Returns the current ref of the code (may not be a commit id, if not saved) Returns ------- commit_id : str the current commit_id (this may not be a commit id) Raises ------ CodeNotInitialized error if not initialized (must initialize first) """ if not self.is_initialized: raise CodeNotInitialized() tracked_filepaths = self._get_tracked_files() return self._calculate_commit_hash(tracked_filepaths)
def check_unstaged_changes(self): """Checks if there exists any unstaged changes for code. Returns False if it's already staged Raises ------ CodeNotInitialized error if not initialized (must initialize first) UnstagedChanges error if not there exists unstaged changes in environment """ if not self.is_initialized: raise CodeNotInitialized() # Check if unstaged changes exist if self._has_unstaged_changes(): raise UnstagedChanges() return False
def checkout_ref(self, commit_id): """Checkout to specific commit Raises ------ CodeNotInitialized error if not initialized (must initialize first) UnstagedChanges error if not there exists unstaged changes in code """ if not self.is_initialized: raise CodeNotInitialized() if not self.exists_ref(commit_id): raise FileIOError( __("error", "controller.code.driver.file.checkout_ref")) # Check if unstaged changes exist if self._has_unstaged_changes(): raise UnstagedChanges() # Check if commit given is same as current tracked_filepaths = self._get_tracked_files() if self._calculate_commit_hash(tracked_filepaths) == commit_id: return True # Remove all tracked files from repository for tracked_filepath in self._get_tracked_files(): absolute_filepath = os.path.join(self.filepath, tracked_filepath) os.remove(absolute_filepath) # Add in files from the commit commit_filepath = os.path.join(self._code_filepath, commit_id) with open(commit_filepath, "r") as f: for line in f: tracked_filepath, filehash = line.rstrip().split(",") source_absolute_filepath = os.path.join( self._code_filepath, tracked_filepath, filehash) destination_absolute_filepath = os.path.join( self.filepath, tracked_filepath) shutil.copy2(source_absolute_filepath, destination_absolute_filepath) return True
def create_ref(self, commit_id=None): """Add all files except for those in .datmoignore, and make a commit If the commit_id is given, it will return the same commit_id or error Parameters ---------- commit_id : str, optional if commit_id is given, it will ensure this commit_id exists and not create a new one Returns ------- commit_id : str, optional if commit_id is given, it will not add files and will not create a commit Raises ------ CodeNotInitialized error if not initialized (must initialize first) CommitDoesNotExist commit id specified does not match a valid commit CommitFailed commit could not be created """ if not self.is_initialized: raise CodeNotInitialized() # If commit is given and it exists then just return it back if commit_id: if not self.exists_ref(commit_id): raise CommitDoesNotExist( __("error", "controller.code.driver.file.create_ref.no_commit", commit_id)) return commit_id # Find all tracked files (_get_tracked_files) tracked_filepaths = self._get_tracked_files() # Create the hash of the files (_calculate_commit_hash) commit_hash = self._calculate_commit_hash(tracked_filepaths) # Check if the hash already exists with exists_ref if self.exists_ref(commit_hash): return commit_hash # Create a new file with the commit hash if it is new, else ERROR (no changes) commit_filepath = os.path.join(self._code_filepath, commit_hash) with open(commit_filepath, "a+") as f: # Loop through the tracked files for tracked_filepath in tracked_filepaths: absolute_filepath = os.path.join(self.filepath, tracked_filepath) absolute_dirpath = os.path.join(self._code_filepath, tracked_filepath) # 1) create dir for file (use path name from tracked files list) -- if already exists skip if not os.path.isdir(absolute_dirpath): os.makedirs(absolute_dirpath) # 2) hash the file filehash = self._get_filehash(absolute_filepath) # 3) add file with file hash as name to folder for the file (if already exists, will overwrite file -- new ts) new_absolute_filepath = os.path.join(absolute_dirpath, filehash) shutil.copy2(absolute_filepath, new_absolute_filepath) # 4) append a line into the new file for the commit hash with the following "filepath, filehash" f.write(tracked_filepath + "," + filehash + "\n") # Return commit hash if success else ERROR return commit_hash