def test_plugins(self, rw_dir): """load all known plugins and dispatch some events""" def raiser(py_file, mod_name): raise AssertionError("loading of plugin '%s' failed") # end prev_dir = os.getcwd() bapp.main().context().push('example plugins') plugin_path = Path(__file__).dirname().dirname() / 'plugins' examples_path = plugin_path.dirname().dirname().dirname() / 'examples' for path in (plugin_path, examples_path): assert path.isdir() assert load_files(path, on_error=raiser) # end for each path to load plugins from try: os.chdir(rw_dir) sg = EventsReadOnlyTestSQLProxyShotgunConnection() engine = EventEngine(sg) for eid in range(1, 1000, 100): sg.next_event_id = sg.first_event_id + eid engine._process_events() # end finally: os.chdir(prev_dir)
def test_delegate(self): dlg_type = ProcessControllerDelegate for path in ('C:\\foo\\bar\\file.ext', '/mnt/share/subdir/file.ext'): path = Path(path) for p in (path, path.dirname()): # can happen with windows paths dirname on posix if not p: continue m = dlg_type.re_find_path.match(p) assert m and m.group(0) == p, "should have found a path in '%s'" % p p = p.replace('/', '-').replace('\\', '-') assert not dlg_type.re_find_path.match(p), "This should be no path '%s'" % p
def pre_start(self, executable, env, args, cwd, resolve): executable, env, new_args, cwd = super(TankCommandDelegate, self).pre_start(executable, env, args, cwd, resolve) # and the second argument must be the tank install root ... lets make it happy if len(new_args) > 2 and not os.path.isabs(new_args[1]): install_root = Path(new_args[0]).dirname().dirname().dirname() assert install_root.basename() == 'install', "Expected first argument '%s' to be tank_cmd.py right in the install root" % new_args[0] new_args.insert(1, install_root.dirname()) # end handle install root last_arg = new_args[-1] if not last_arg.startswith(self.tank_pc_arg): # we assume to be in the right spot, but a check can't hurt until # we are able to do more ourselves actual_executable = self._actual_executable() base = actual_executable.dirname() assert (base / 'tank').exists(), "Currently '%s' must be right next to the 'tank' executable" % executable new_args.append(str(self.tank_pc_arg + base)) # end setup context ####################### # Process Arguments ## ##################### if len(new_args) > 6 and new_args[3].startswith(self.launch_prefix): # now we could go crazy and try to find asset paths in order to provide context to bprocess # We could also use the shotgun context in some way, to feed data to our own asset management # However, for now using the project itself should just be fine, but this is certainly # to be improved # Additinally, what we really want is to start any supported program, and enforce tank support by # fixing up delegates. For that, we will create a new process controller, which uses our Application # instance, and the delegate that it defined so far. # However, we are currently unable to truly provide the information we have to a new process controller, # unless it's communicated via the context. # It should be one of ours (e.g. TankEngineDelegate derivative) if there is tank support, which # requires proper configuration. # For that to work, we will override the entire start procedure, as in pre-start we can't and should not # swap in the entire delegate def set_overrides(schema, value): value.host_app_name = new_args[3][len(self.launch_prefix):] value.entity_type = new_args[4] value.entity_id = int(new_args[5]) # end overrides setter # This call will also push the context onto the stack, nothing more to be done here self.ApplyChangeContextType('tank-engine-information').setup(self._app.context(), set_overrides, tank_engine_schema) #end handle particular command mode return (executable, env, new_args, cwd)
def prepare_context(self, executable, env, args, cwd): """We will parse paths from the given commandline and use them in the context we build. Additionaly, we will provide a per-arg handler with the opportunity to inject kvstore overrides """ # Will be a kvstore if there have been overrides kvstore_overrides = KeyValueStoreModifier(dict()) for arg in args: # by default, we use paths as as context provider (configurable) path = self._extract_path(arg) if path: # ignore args that are not paths path = Path(path) if path.dirname().isdir(): self._app.context().push(self.StackAwareHierarchicalContextType(path.dirname())) # end handle valid directory # end handle path self.handle_argument(arg, kvstore_overrides) # end for each arg to check # set overrides if list(kvstore_overrides.keys()): self._app.context().push(Context('delegate overrides', kvstore_overrides)) # end handle overrides return super(ProcessControllerDelegate, self).prepare_context(executable, env, args, cwd)
def __init__(self, *args, **kwargs): """Initialize this instance with the required operations and verify configuration @throw ValueError if our configuration seems invalid""" super(TransferDropboxTransaction, self).__init__(*args, **kwargs) # Prepare the kvstore with data for resolving values now = datetime.utcnow() store = self._kvstore store.set_value('Y', now.year) store.set_value('M', now.month) store.set_value('D', now.day) store.set_value('H', now.hour) store.set_value('MIN', now.minute) config = self._config() if config.mode not in self.valid_modes: raise ValueError("Invalid transfer mode '%s' - must be one of %s" % (config.mode, ','.join(self.valid_modes))) # end check mode if not config.destination_dir.isdir(): raise ValueError("Destination dropbox was not accessible: '%s'" % config.destination_dir) # prepare and resolve destination # handle subdir and create it if needed if config.subdir: raise NotImplementedError("implement unique identifier and subdir creation") # end source = self._sql_instance.in_package.root() destination = config.destination_dir is_sync_mode = config.mode == self.MODE_SYNC if config.keep_package_subdir: # NOTE: rsync will duplicate our first directory unless we truncate it here root_relative = Path(self._package.root_relative()) if root_relative.dirname(): destination /= root_relative.dirname() # end handle modification of destination if is_sync_mode: if not source.isdir(): log.warn("Using copy instead of sync as it would be dangerous to use if there is no package subdirectory - source is file") is_sync_mode = False else: # In case of sync, we want to use the most destination path. This is possibly by instructing # rsync to copy only the directory contents, into a destination which carries the additional # base name of the source directory destination = destination / source.basename() source += '/' # end put in sync mode safety # end adjust source-destination for sync mode # Make sure the directory exists if not destination.isdir(): destination.makedirs() # end handle dir creation elif is_sync_mode: log.warn("Deactivating sync-mode as it is dangerous to use if keep_package_subdir is disabled") is_sync_mode = False # end handle subdir rsync_args = is_sync_mode and ['--delete'] or list() TransferRsyncOperation(self, source, destination, move=config.mode==self.MODE_MOVE, additional_rsync_args=rsync_args) self._sql_instance.comment = "%sing package from '%s' to '%s'" % (config.mode, source, destination)