...
 
Commits (3)
......@@ -2,7 +2,7 @@
#
# AWL simulator - source management
#
# Copyright 2014-2018 Michael Buesch <m@bues.ch>
# Copyright 2014-2019 Michael Buesch <m@bues.ch>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
......@@ -56,6 +56,7 @@ class SourceFactory(XmlFactory):
name = tag.getAttr("name", source.SRCTYPE)
filename = tag.getAttr("file", "")
enabled = tag.getAttrBool("enabled", True)
volatile = tag.getAttrBool("volatile", False)
if source.SRCTYPE_ID != srcType:
raise self.Error("SourceFactory: Got unexpected "
"source type %d instead of %d." % (
......@@ -67,6 +68,7 @@ class SourceFactory(XmlFactory):
source.filepath = ""
source.name = name
source.enabled = enabled
source.volatile = volatile
self.__haveSourceTag = True
def parser_beginTag(self, tag):
......@@ -141,6 +143,7 @@ class SourceFactory(XmlFactory):
"file" : str(filename),
"name" : str(source.name),
"enabled" : "1" if source.enabled else "0",
"volatile" : "1" if source.volatile else "",
},
data=data,
tags=childTags,
......@@ -164,7 +167,8 @@ class GenericSource(object):
enabled=True,
filepath="",
sourceBytes=b"",
userData={}):
userData={},
volatile=False):
"""Initialize a source code object.
name: Name string of the source.
enabled: True, if the source is active.
......@@ -174,12 +178,16 @@ class GenericSource(object):
The source code object will not touch this data.
This data will _not_ be transferred to the core server.
This data does _not_ contribute to the identHash.
volatile: Optional flag: This source is volatile.
Such sources will not be stored in the core server project.
This flag does _not_ contribute to the identHash.
"""
self.name = name
self.enabled = enabled
self.filepath = filepath
self.sourceBytes = sourceBytes
self.userData = userData.copy()
self.volatile = volatile
self.__identHash = None
......@@ -201,6 +209,14 @@ class GenericSource(object):
self.__enabled = bool(enabled)
self.__identHash = None
@property
def volatile(self):
return self.__volatile
@volatile.setter
def volatile(self, volatile):
self.__volatile = bool(volatile)
@property
def filepath(self):
return self.__filepath
......@@ -358,7 +374,8 @@ class GenericSource(object):
enabled=self.enabled,
filepath=self.filepath,
sourceBytes=self.sourceBytes[:],
userData=self.userData)
userData=self.userData,
volatile=self.volatile)
def copyFrom(self, other,
copyName=True,
......@@ -366,7 +383,8 @@ class GenericSource(object):
copyFilepath=True,
copySourceBytes=True,
copyUserData=True,
updateUserData=False):
updateUserData=False,
copyVolatile=True):
"""Copy the content of another source into this one.
"""
if copyName:
......@@ -381,6 +399,8 @@ class GenericSource(object):
self.userData = other.userData.copy()
if updateUserData:
self.userData.update(other.userData)
if copyVolatile:
self.volatile = other.volatile
def __eq__(self, other):
return self.identHash == other.identHash
......@@ -389,11 +409,12 @@ class GenericSource(object):
return not self.__eq__(other)
def __repr__(self):
return "%s%s %s%s %s" % (
return "%s%s %s%s%s %s" % (
self.SRCTYPE,
"" if self.isFileBacked() else " project",
self.name,
"" if self.enabled else " (DISABLED)",
" (VOLATILE)" if self.volatile else "",
self.identHashStr)
class AwlSource(GenericSource):
......
......@@ -201,7 +201,7 @@ def safeFileWrite(filename, data):
if not osIsPosix: #@nocov
# Can't use safe rename on non-POSIX.
# Must unlink first.
with contextlib.suppress(OSError):
with contextlib.suppress(IOError, OSError):
os.unlink(filename)
os.rename(tmpFile, filename)
except (IOError, OSError) as e: #@nocov
......
......@@ -2,7 +2,7 @@
#
# AWL simulator - PLC core server
#
# Copyright 2013-2018 Michael Buesch <m@bues.ch>
# Copyright 2013-2019 Michael Buesch <m@bues.ch>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
......@@ -519,10 +519,16 @@ class AwlSimServer(object): #+cdef
def __generateProject(self):
cpu = self.__sim.getCPU()
awlSources = self.awlSourceContainer.getSources()
fupSources = self.fupSourceContainer.getSources()
awlSources = [ source
for source in self.awlSourceContainer.getSources()
if not source.volatile ]
fupSources = [ source
for source in self.fupSourceContainer.getSources()
if not source.volatile ]
kopSources = [] #TODO
symTabSources = self.symTabSourceContainer.getSources()
symTabSources = [ source
for source in self.symTabSourceContainer.getSources()
if not source.volatile ]
libSelections = self.loadedLibSelections[:]
cpuSpecs = cpu.getSpecs() # (Note: not a deep-copy)
cpuConf = cpu.getConf() # (Note: not a deep-copy)
......@@ -1145,16 +1151,33 @@ class AwlSimServer(object): #+cdef
if not project:
return
printDebug("Loading project '%s'" % str(project))
if isString(project):
if fileExists(project) == False and writeBack:
projectFile = project
if writeBack:
# If the project file exists and it has zero size
# then delete the file.
if fileExists(projectFile):
with contextlib.suppress(IOError, OSError):
if not os.path.getsize(projectFile):
os.unlink(projectFile)
printInfo("Purged empty project "
"file at '%s'." % projectFile)
if not fileExists(projectFile):
# The project file does not exist.
# Create an empty one.
printInfo("Creating empty project at '%s'" %\
project)
empty = Project(project)
printInfo("Creating empty project at '%s'" % (
projectFile))
empty = Project(projectFile)
empty.toFile()
project = Project.fromProjectOrRawAwlFile(project)
printDebug("Loading project '%s'" % str(project))
# Load the project data.
try:
project = Project.fromFile(projectFile)
except AwlSimError as e:
raise AwlSimError("AwlSimServer: "
"Failed to load project file '%s':\n%s" % (
projectFile, e.message))
self.__resetAll()
......
......@@ -2,7 +2,7 @@
#
# AWL simulator - FUP compiler
#
# Copyright 2016-2018 Michael Buesch <m@bues.ch>
# Copyright 2016-2019 Michael Buesch <m@bues.ch>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
......@@ -432,7 +432,8 @@ class FupCompiler(object):
name = "%s (Compiled from FUP/FBD source)" % fupSource.name
self.awlSource = AwlSource(name=name,
enabled=fupSource.enabled,
filepath=fupSource.filepath)
filepath=fupSource.filepath,
volatile=True)
if self.__parse():
self.__compileBlockDecl()
insns = self.__compileGrids()
......@@ -489,7 +490,8 @@ class FupCompiler(object):
awlLines.append("\t)")
awlString = "\r\n".join(awlLines)
awlSource = AwlSource(name=("CALL " + self.fupSource.name))
awlSource = AwlSource(name=("CALL " + self.fupSource.name),
volatile=True)
awlSource.sourceBytes = awlString.encode(AwlSource.ENCODING)
return awlSource
......