def addFileOp(self, cmd, context, source, output_path): # Try to detect if our output_path is actually a folder, via trailing # slash or '.'/'' indicating the context folder. detected_folder = None if util.IsString(output_path): if output_path[-1] == os.sep or output_path[-1] == os.altsep: detected_folder = os.path.join(context.buildFolder, os.path.normpath(output_path)) elif output_path == '.' or output_path == '': detected_folder = context.buildFolder # Since we're building something relative to the context folder, ensure # that the context folder exists. self.getLocalFolder(context) else: assert output_path.type != nodetypes.Source local_path = os.path.relpath(output_path.path, context.buildFolder) detected_folder = os.path.join(context.buildFolder, local_path) detected_folder = os.path.normpath(detected_folder) source_entry = self.parseInput(context, source) # This is similar to a "cp a b/", so we append to get "b/a" as the path. if detected_folder is not None: base, output_path = os.path.split(source_entry.path) assert len(output_path) output_folder = detected_folder else: output_folder = context.buildFolder output_path = nodetypes.combine(output_folder, output_path) # For copy operations, it's okay to use the path from the current folder. # However, when performing symlinks, we always want an absolute path. if cmd == nodetypes.Symlink: if source_entry.type == nodetypes.Source: source_path = source_entry.path else: source_path = os.path.join(context.buildPath, source_entry.path) else: source_path = source_entry.path # For clarity of spew, we always execute file operations in the root of # the build folder. This means that no matter what context we're in, # we can use absolute-ish folders and get away with it. return self.addCommand(context=context, node_type=cmd, folder=None, data=(source_path, output_path), inputs=[source_entry], outputs=[output_path])
def addFileOp(self, cmd, context, source, output_path): # Try to detect if our output_path is actually a folder, via trailing # slash or '.'/'' indicating the context folder. detected_folder = None if util.IsString(output_path): if output_path[-1] == os.sep or output_path[-1] == os.altsep: detected_folder = os.path.join(context.buildFolder, os.path.normpath(output_path)) elif output_path == '.' or output_path == '': detected_folder = context.buildFolder # Since we're building something relative to the context folder, ensure # that the context folder exists. self.getLocalFolder(context) else: assert output_path.type != nodetypes.Source local_path = os.path.relpath(output_path.path, context.buildFolder) detected_folder = os.path.join(context.buildFolder, local_path) detected_folder = os.path.normpath(detected_folder) source_entry = self.parseInput(context, source) # This is similar to a "cp a b/", so we append to get "b/a" as the path. if detected_folder is not None: base, output_path = os.path.split(source_entry.path) assert len(output_path) output_folder = detected_folder else: output_folder = context.buildFolder output_path = nodetypes.combine(output_folder, output_path) # For copy operations, it's okay to use the path from the current folder. # However, when performing symlinks, we always want an absolute path. if cmd == nodetypes.Symlink: if source_entry.type == nodetypes.Source: source_path = source_entry.path else: source_path = os.path.join(context.buildPath, source_entry.path) else: source_path = source_entry.path # For clarity of spew, we always execute file operations in the root of # the build folder. This means that no matter what context we're in, # we can use absolute-ish folders and get away with it. return self.addCommand( context = context, node_type = cmd, folder = None, data = (source_path, output_path), inputs = [source_entry], outputs = [output_path] )
def parseOutput(self, cwd_entry, path, kind): if path[-1] == os.sep or path[ -1] == os.altsep or path == '.' or path == '': util.con_err(util.ConsoleRed, 'Path "', util.ConsoleBlue, path, util.ConsoleRed, '" looks like a folder; a folder was not expected.', util.ConsoleNormal) raise Exception('Expected folder, but path has a trailing slash') path = os.path.normpath(path) path, name = os.path.split(path) path = nodetypes.combine(cwd_entry, path) # We should have caught a case like 'x/' earlier. assert len(name) # If we resolved that there is no prefix path, then take this to mean the # root folder. if path: folder_entry = self.validateOutputFolder(path) output_path = os.path.join(path, name) else: folder_entry = None output_path = name entry = self.db.query_path(output_path) if not entry: if self.refactoring: util.con_err(util.ConsoleRed, 'New output file introduced: ', util.ConsoleBlue, output_path, util.ConsoleNormal) raise Exception('Refactoring error') return self.db.add_output(folder_entry, output_path, kind) if entry.type == kind: return entry if entry.type == nodetypes.Mkdir: if entry not in self.old_folders_: util.con_err(util.ConsoleRed, 'A folder is being re-used as an output file: "', util.ConsoleBlue, entry.path, util.ConsoleRed, '"', util.ConsoleNormal) raise Exception( 'Attempted to re-use a folder as generated file') if self.refactoring: util.con_err( util.ConsoleRed, 'A generated folder has changed to a generated file: ', util.ConsoleBlue, entry.path, util.ConsoleNormal) raise Exception('Refactoring error') # We keep the node in old_folders_. This should be okay, since we've # changed the type to Output now. This way we can stick to one folder # deletion routine, since it's fairly complicated. elif entry.type == nodetypes.Output: # If we're asking for a shared output, make sure we can reuse this one. input_cmd = self.db.query_command_of(entry) if input_cmd and input_cmd not in self.old_commands_: util.con_err(util.ConsoleRed, 'First defined with command: ', input_cmd.format(), util.ConsoleNormal) raise Exception( 'Existing output cannot be a shared output: {0}'.format( entry.path)) if self.refactoring: util.con_err(util.ConsoleRed, 'An output has changed to a shared output: ', util.ConsoleBlue, entry.path, util.ConsoleNormal) raise Exception('Refactoring error') elif entry.type == nodetypes.SharedOutput: input_cmds = self.db.query_shared_commands_of(entry) for input_cmd in input_cmds: if input_cmd not in self.old_commands_: util.con_err( util.ConsoleRed, 'A shared output cannot be specified as an normal output.', util.ConsoleNormal) raise Exception( 'Existing shared output cannot be a normal output: {0}' .format(entry.path)) if self.refactoring: util.con_err( util.ConsoleRed, 'A shared output has changed to a normal output: ', util.ConsoleBlue, entry.path, util.ConsoleNormal) raise Exception('Refactoring error') else: util.con_err( util.ConsoleRed, 'An existing node has been specified as an output file: "', util.ConsoleBlue, entry.format(), util.ConsoleRed, '"', util.ConsoleNormal) raise Exception( 'Attempted to re-use an incompatible node as an output') self.db.change_to_output(entry, kind) return entry
def parseOutput(self, cwd_entry, path, kind): if path[-1] == os.sep or path[-1] == os.altsep or path == '.' or path == '': util.con_err(util.ConsoleRed, 'Path "', util.ConsoleBlue, path, util.ConsoleRed, '" looks like a folder; a folder was not expected.', util.ConsoleNormal) raise Exception('Expected folder, but path has a trailing slash') path = os.path.normpath(path) path, name = os.path.split(path) path = nodetypes.combine(cwd_entry, path) # We should have caught a case like 'x/' earlier. assert len(name) # If we resolved that there is no prefix path, then take this to mean the # root folder. if path: folder_entry = self.validateOutputFolder(path) output_path = os.path.join(path, name) else: folder_entry = None output_path = name entry = self.db.query_path(output_path) if not entry: if self.refactoring: util.con_err(util.ConsoleRed, 'New output file introduced: ', util.ConsoleBlue, output_path, util.ConsoleNormal) raise Exception('Refactoring error') return self.db.add_output(folder_entry, output_path, kind) if entry.type == kind: return entry if entry.type == nodetypes.Mkdir: if entry not in self.old_folders_: util.con_err(util.ConsoleRed, 'A folder is being re-used as an output file: "', util.ConsoleBlue, entry.path, util.ConsoleRed, '"', util.ConsoleNormal) raise Exception('Attempted to re-use a folder as generated file') if self.refactoring: util.con_err(util.ConsoleRed, 'A generated folder has changed to a generated file: ', util.ConsoleBlue, entry.path, util.ConsoleNormal) raise Exception('Refactoring error') # We keep the node in old_folders_. This should be okay, since we've # changed the type to Output now. This way we can stick to one folder # deletion routine, since it's fairly complicated. elif entry.type == nodetypes.Output: # If we're asking for a shared output, make sure we can reuse this one. input_cmd = self.db.query_command_of(entry) if input_cmd and input_cmd not in self.old_commands_: util.con_err(util.ConsoleRed, 'First defined with command: ', input_cmd.format(), util.ConsoleNormal) raise Exception('Existing output cannot be a shared output: {0}'.format(entry.path)) if self.refactoring: util.con_err(util.ConsoleRed, 'An output has changed to a shared output: ', util.ConsoleBlue, entry.path, util.ConsoleNormal) raise Exception('Refactoring error') elif entry.type == nodetypes.SharedOutput: input_cmds = self.db.query_shared_commands_of(entry) for input_cmd in input_cmds: if input_cmd not in self.old_commands_: util.con_err(util.ConsoleRed, 'A shared output cannot be specified as an normal output.', util.ConsoleNormal) raise Exception('Existing shared output cannot be a normal output: {0}'.format(entry.path)) if self.refactoring: util.con_err(util.ConsoleRed, 'A shared output has changed to a normal output: ', util.ConsoleBlue, entry.path, util.ConsoleNormal) raise Exception('Refactoring error') else: util.con_err(util.ConsoleRed, 'An existing node has been specified as an output file: "', util.ConsoleBlue, entry.format(), util.ConsoleRed, '"', util.ConsoleNormal) raise Exception('Attempted to re-use an incompatible node as an output') self.db.change_to_output(entry, kind) return entry