3 # Copyright (C) 2003 Stuart Brorson <sdb@cloud9.net>
5 #------------------------------------------------------------------
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #-------------------------------------------------------------------
22 This program is used to create a gEDA design archive. It operates in two
23 modes: archive mode and extract mode. In archive mode it creates a
24 project archive from a bunch of project files, and in extract mode it
25 extracts the files from the archive and places them in the local dir.
29 Information about program invocation is held in the Usage string below.
31 --- Archive mode algorithm:
32 1. It gets the local directory name, as well as a bunch of info from the
33 command line & stores all the info in the object "Args". Then it
34 cd's into /tmp (ScratchDirectory).
35 2. It gets the symbol library search path from $(GEDADATADIR)/
36 gschemrc-common and ./gschemrc & creates a list of all search
37 paths. Note that the system-dependent search path is hardcoded into
38 the script by "make" when the file is installed.
39 3. It reads the list of files to archive from ./garchiverc (or the -f
40 substitute) and the command line and creates an internal list of files to
42 4. It finds the .sch files among the archive list, and creates an internal
43 list of schem files process/archive.
44 5. For each schem file in the list, it opens the file, runs through it,
45 and builds a list of symbols used in that file. Naturally, duplicate
47 6. It opens a directory called /tmp/garchive-symbols. For each symbol
48 file in the symbol file list, it gets the file from $(GEDADATADIR)/sym
49 and sticks it into ./garchive-symbols.
50 7. It takes the local gschemrc, and munges it so that gschem will find
51 all symbols in ./garchive-symbols.
52 8. It then creates a tar archive of the following:
53 * All files listed in garchiverc and/or the command line.
54 * The entire ./garchive-symbols directory
57 9. The prog then gzips the tar archive, renames it to the name
58 specified by the user, and sticks it in the user's directory
59 10. It then cd's back to the local directory & deletes the leftover
60 cruft from /tmp (or ScratchDirectory).
62 Important data structures during creation of archive:
63 * LibraryPathList -- list of paths to symbol libraries.
64 * ArchiveFileList -- list of all files to archive. Includes gschemrc and
65 garchiverc, as well as garchive-symbols/
66 * SchemFileList -- list of schematic files found.
67 * SymbolFileList -- list of symbol files found. Duplicates are ignored.
69 --- Extract mode algorithm:
70 1. Copy archive file into /tmp (or ScratchDirectory).
71 2. Create a list of archive's contents using "tar -t -f ProjectArchive"
72 3. Extract files into /tmp
73 3. Loop on file list. Move each file into user's directory.
74 Before each move, make sure that no overwrite of existing files will occur.
75 After each iteration, clean up the cruft left in /tmp.
77 Note: File names used internally have no / prefix. Dir names have no / suffix.
78 Therefore, must include / manually in each case.
80 --- TBD suggestions from users:
81 None right now . . . .
84 20031114 -- First (alpha) version by SDB.
85 20031121 -- Incorporated SPICE file archiving. Now get /tmp dir from
86 environment. Presence of RC files is now optional -- user
87 is queried about creating them if they don't exist.
88 20031204 -- Changed program so that it keeps .tar.gz as the archive file
89 suffix due to popular demand.
91 ############################################################################
92 import sys
, copy
, string
, getopt
, re
, os
, commands
94 ############################################################################
95 # Helper fcns and data structures. #
96 ############################################################################
98 #---------------------------------------------------------------------------
99 # This is the help string.
102 garchive -- the gEDA archiving utility. Used to create as well as extract
103 gEDA designs from an archive. The two modes of operation are "archive mode"
104 (archive creation) and "extract mode". Archive mode is the default.
106 Command line switches:
107 -f <filename> -- Optional. Used in archive mode. Read files to archive from
108 <filename> instead of garchiverc.
109 -v -- Optional. Verbose mode. Used in both archive and extract mode.
110 Spews lots of info about what the prog is doing.
111 -e -- Mandatory if you want to extract. Extract mode.
112 Open up the archive specified on the command line.
113 -a -- Optional. Archive mode. Archive mode (i.e. create a project
114 archive) is the default; this flag exists to give people
115 the warm and fuzzies.
116 -o <outfile> -- Optional. Used in archive mode. Specifies the name of
117 the output archive file. The output file extension
118 should be ".tar.gz". If this flag is not specified, the
119 output file name is "ProjectArchive.tar.gz".
122 Create an archive named MyArchive.tar.gz (files to store listed in garchiverc):
123 garchive -o MyArchive.tar.gz
125 Verbosely create an archive (archives files listed on cmd line
126 as well as those listed in garchiverc):
127 garchive -v -o MyArchive.tar.gz README Schematic1.sch Schematic2.sch Schematic3.sch
130 garchive -e ProjectArchive.tar.gz
132 Copyright (C) 2003 by SDB. Released under the GPL.
135 #---------------------------------------------------------------------------
136 def DebugSpew(Args
, String
):
138 This prints out String when the -v flag is set, otherwise is silent
140 if (Args
.VerboseMode
== "verbose"):
141 print("---- "+ String
)
144 #---------------------------------------------------------------------------
145 def CheckFilename(Filename
):
147 This checks a string to make sure that it is a valid filename.
148 It currently doesn't do very much. . . .
150 if (re
.search('\.tar\.gz$', Filename
)):
156 #----------------------------------------------------------------------
157 def NormalizePath(SearchDir
, DirName
):
159 This fcn expands environment variables like ${GEDADATA} and ${HOME}
160 in full absolute file/directory names.
161 Environment vars must be in the form ${foo}.
162 It expects to see a directory or file name like "${foo}/bar/baz/".
163 Only one env var may be expanded at a time. SearchDir is the base
164 directory from which all relative paths are normalized.
166 # First replace environment var
167 if re
.match('\${[\w]+}', DirName
):
168 Match
= re
.search('(\${)([\w]+)(}/)([\w/]+)', DirName
)
169 EnvVar
= Match
.group(2)
171 # Need to make sure that something exists beyond ${ENVVAR}
173 Remainder
= Match
.group(4)
177 # Check if env variable is ${GEDADATA}. If so, just replace it with Args.GedaDataDir
178 if (EnvVar
== "GEDADATA"):
179 EnvVar
= Args
.GedaDataDir
181 # Try to get environment variable
183 EnvVar
= os
.environ
[EnvVar
]
185 print ("Env variable "+EnvVar
+" not defined in current environment")
186 print ("Try setting it. . . .")
189 DirName
= EnvVar
+"/"+Remainder
191 # Now cd into SearchDir and perform a filename normalization
192 # (to get rid of .. . and other relative file paths . . .)
194 CurrentDir
= os
.getcwd()
196 DirName
= os
.path
.abspath(DirName
)
202 #---------------------------------------------------------------------------
205 This class holds info about the environment and cmd line args passed to the
206 program. It has only one method: the constructor, which gets the args
207 and fills out the public vars. The public vars are:
209 ProgramMode = "archive", "extract"
210 OutputFileName (archive only) = the name of the archive. default = ProjectArchive.tar.gz
211 InputFileNames = [list of input files on command line]
212 RcFileName (archive only) = name of garchiverc to use (instead of garchiverc)
213 VerboseMode = "quiet", "verbose"
214 FilesToArchiveList (archive only)
215 UserDir = Directory holding files to archive. (Directory where garchive was invoked.)
216 ScratchDir = "/tmp" by default
217 FileArchiveDir = "gschem-files" by default
218 GedaDataDir = directory holding GEDA data & files such as "system-gafrc"
222 Constructor: parse through cmd line args and fill out vars.
224 self
.VerboseMode
= "quiet" # default
225 self
.ProgramMode
= "archive" # default
226 self
.GarchiveRcFileName
= "garchiverc" # default
227 self
.GschemRcFileName
= "gschemrc" # default
228 self
.OutputFileName
= "ProjectArchive.tar.gz" # default
229 self
.UserDir
= os
.path
.abspath(os
.getcwd())
230 self
.FileArchiveDir
= "gschem-files" # default
232 # Get GedaDataDir -- this will be set by the Makefile, which does
233 # an sed replacement of GEDADATADIR
234 self
.GedaDataDir
= "GEDADATADIR"
235 # self.GedaDataDir = "/home/binaries/geda/share/gEDA" # Used for debug
237 # Get ScratchDir, either from environment, or just use /tmp as default.
238 for EnvVar
in ["TMP", "TMPVAR", "TEMP"]:
240 TempDir
= os
.environ
[EnvVar
]
242 continue # Not present, continue looping
244 self
.ScratchDir
= TempDir
# Got it!
247 self
.ScratchDir
= "/tmp" # no env var set, use default
249 # Get and process command line args
251 OptList
, Args
= getopt
.getopt(sys
.argv
[1:], 'aef:ho:v')
253 print Usage
# print out usage string if
254 # user uses invalid flag.
257 # First pass through args. Get switch settings & set program modes.
258 for Option
, Value
in OptList
:
261 self
.ProgramMode
= "archive"
264 self
.ProgramMode
= "extract"
267 self
.VerboseMode
= "verbose"
273 # Second pass. Do sanity checking and get configured filenames.
274 for Option
, Value
in OptList
:
277 if self
.ProgramMode
== "extract": # sanity check
278 raise SyntaxError("Incompatible command line args")
281 if self
.ProgramMode
== "archive": # sanity check
282 raise SyntaxError("Incompatible command line args")
285 if self
.ProgramMode
== "extract": # sanity check
286 raise SyntaxError("Incompatible command line args")
290 print("Resource file "+Value
+" doesn't exist. Exiting.")
293 self
.GarchiveRcFileName
= Value
#strcopy?
296 if self
.ProgramMode
== "extract": # sanity check
297 raise SyntaxError("Incompatible command line args")
298 if CheckFilename(Value
):
299 self
.OutputFileName
= Value
#strcopy?
301 print("Warning -- output file suffix is not \".tar.gz\" -- the")
302 print("extractor won't know how to deal with your archive.")
303 Input
= raw_input("Continue? [y/N] ")
304 if ( (len(Input
) == 0) or (Input
[0] != "y") ):
307 self
.OutputFileName
= Value
309 # Third step: Create list of files remaining on command line, and create output
311 self
.CmdLineFileList
= Args
313 self
.OutputFileNameBase
= re
.sub('\.tar\.gz', '', self
.OutputFileName
)
318 #---------------------------------------------------------------------------
319 def GetLibraryPath(Args
):
321 This fcn takes the library search path from the local dir and the system
324 DebugSpew(Args
, "Now in GetLibraryPath.")
327 LocalRCFileName
= Args
.UserDir
+"/"+Args
.GschemRcFileName
328 SystemRCFileName
= Args
.GedaDataDir
+"/system-gafrc"
330 # Now read in system rc file and create sym lib path
331 DebugSpew(Args
, "Processing system resource file "+SystemRCFileName
)
333 SysFile
= open(SystemRCFileName
, "r")
335 print("Unable to find system resource file "+SystemRCFileName
+".")
338 for line
in SysFile
.readlines():
339 # Match "(component-library " string. . . .
340 if re
.match('^\(component-library ', line
):
341 Match
= re
.search('(")([{$}\w/]+)(")', line
)
343 Dir
= NormalizePath(Args
.GedaDataDir
, Dir
) # Expand any env variables such as ${GEDADATA}. . .
345 # DebugSpew(Args, "Sticking "+Dir+" into LibraryPathList")
346 LibraryPathList
.append(Dir
)
348 # Match "(component-library-search " string. . . .
349 if re
.match('^\(component-library-search', line
):
350 Match
= re
.search('(")([{$}\w/]+)(")', line
)
352 Dir
= NormalizePath(Args
.GedaDataDir
, Dir
) # Expand any env variables such as ${GEDADATA}. . .
354 if Dir
in LibraryPathList
:
357 # DebugSpew(Args, "Sticking "+Dir+" into LibraryPathList")
358 LibraryPathList
.append(Dir
)
362 # Next read in LocalRCFileName
363 DebugSpew(Args
, "Processing local resource file "+LocalRCFileName
)
365 LocalFile
= open(LocalRCFileName
, "r")
367 Input
= raw_input(LocalRCFileName
+" doesn't exist. Create empty version in local dir? [Y/n] ")
368 if ( (len(Input
) == 0) or (Input
[0] != "n") ):
369 os
.system("touch "+LocalRCFileName
)
371 print("You need "+LocalRCFileName
+" to create archive. Aborting.")
374 for line
in LocalFile
.readlines():
375 if re
.match('^\(component-library ', line
):
376 Match
= re
.search('(")([\S]+)(")', line
) # Note additional . to search for
378 Dir
= NormalizePath(Args
.UserDir
, Dir
) # Expand any env variables and ./
380 if Dir
in LibraryPathList
:
383 # DebugSpew(Args, "Sticking "+Dir+" into LibraryPathList")
384 LibraryPathList
.append(Dir
)
388 # Reverse list because that's how it is searched
389 LibraryPathList
.reverse()
391 return LibraryPathList
393 #---------------------------------------------------------------------------
394 def CreateArchiveFileList(Args
):
396 This creates the list of files in the archive. It starts with
397 known files, and then adds the names of the files to archive,
398 given either at the command line or in the garchiverc file.
400 DebugSpew(Args
, "Now in CreateArchiveFileList.")
403 # Start with known file names
404 PotentialArchFileList
= [Args
.UserDir
+"/"+Args
.GschemRcFileName
, Args
.UserDir
+"/"+Args
.GarchiveRcFileName
] # Could use map here. . .
406 # Make sure each file exists and can be saved
407 for FileName
in PotentialArchFileList
:
408 if (os
.path
.isfile(FileName
) or os
.path
.isdir(FileName
)):
409 FileName
= NormalizePath(Args
.UserDir
, FileName
) # Just make sure filename is kosher. . . .
410 ArchFileList
.append(FileName
)
412 Input
= raw_input(FileName
+" doesn't exist. Create empty version in local dir? [Y/n] ")
413 if ( (len(Input
) == 0) or (Input
[0] != "n") ):
414 print("Creating "+FileName
+" in archive.")
415 os
.system("touch "+FileName
)
416 ArchFileList
.append(FileName
)
418 print("You need "+FileName
+" to create archive. Aborting.")
421 # Add the gschem-files dir /tmp/gschem-files
422 ArchFileList
.append(Args
.ScratchDir
+"/"+Args
.FileArchiveDir
) # We build the archive dir in /tmp
424 # Now get names of all schematics and other files to archive.
426 # First get file names from command line
427 DebugSpew(Args
, "Examining files listed on command line")
428 for File
in Args
.CmdLineFileList
:
429 File
= NormalizePath(Args
.UserDir
, File
)
430 DebugSpew(Args
, "Examining "+File
+" for inclusion in archive")
431 if (File
in ArchFileList
):
432 break # Don't include file if it's already there.
436 print("File "+File
+" listed in command line doesn't exist. Ignoring. . .")
439 ArchFileList
.append(File
)
441 # Next get file names from file, if specified.
442 GarchiveRCFile
= open(Args
.UserDir
+"/"+Args
.GarchiveRcFileName
, "r")
443 DebugSpew(Args
, "Examining files listed in "+Args
.GarchiveRcFileName
)
445 FileName
= GarchiveRCFile
.readline()
449 FileName
= re
.sub('[\n\s]+', '', FileName
) # Strip out \n chars & whitespace
450 FileName
= NormalizePath(Args
.UserDir
, FileName
)
451 DebugSpew(Args
, "Examining "+FileName
+" for inclusion in archive")
456 print("File "+FileName
+" listed in "+Args
.GarchiveRcFileName
+" doesn't exist. Ignoring. . .")
459 FileName
= NormalizePath(Args
.UserDir
, FileName
)
460 if (FileName
in ArchFileList
):
463 ArchFileList
.append(FileName
)
467 #---------------------------------------------------------------------------
468 def CreateSchemFileList(Args
, FileList
):
470 This creates the list of schem files to search. Right now I just
471 run through FileList and pull out all files ending in .sch.
472 Files are saved in list with basename (no path).
474 DebugSpew(Args
, "Now in CreateSchemFileList.")
476 for File
in FileList
:
478 if re
.search('\.sch$', File
): # re.search matches occurance anywhere
480 # Need to make sure schem file actually exists
481 # There is probably a better way to do this using os.access, but I was
482 # not able to get it to work. . . . .
484 TestFile
= open(File
, "r")
486 print("Can't access "+File
+" for reading. Exiting . . . .")
490 # Next we need to make sure that this file is not already in the list.
491 if File
in SchemFileList
:
494 SchemFileList
.append( os
.path
.basename(File
) )
498 #---------------------------------------------------------------------------
499 def CreateSymbolFileList(SchemFileList
, LibraryFileList
):
501 This fcn opens each .sch file found and looks for symbol files
502 (typically lurking in lines like "C 32400 53000 1 0 0 resistor-1.sym").
503 When it finds a symbol file, it looks up the file's entire path, and then
504 sticks it in the SymbolFileList.
506 DebugSpew(Args
, "Now in CreateSymbolFileList.")
507 SymbolFileList
= [] # List starts as empty
509 for SchemFileName
in SchemFileList
:
510 SchemFile
= open(SchemFileName
, "r")
511 for line
in SchemFile
.readlines():
512 # Match component line C 32400 53000 1 . . . . .
513 if re
.match('^C ', line
):
514 Match
= re
.match('(C )([\d]+ )([\d]+ )([\d]+ )([\d]+ )([\d]+ )([\d\w\-\./]+)', line
)
515 SymFile
= Match
.group(7)
517 # DebugSpew(Args, "Found "+SymFile+" in schematic "+SchemFileName)
519 # Now find path for symbol file & stick it in list
520 for LibPath
in LibraryFileList
:
521 AbsSymFileName
= os
.path
.abspath(LibPath
+"/"+SymFile
)
522 if os
.path
.isfile(AbsSymFileName
):
523 # Insert in list if not already there.
524 if AbsSymFileName
in SymbolFileList
:
527 SymbolFileList
.append(AbsSymFileName
)
529 return SymbolFileList
531 #---------------------------------------------------------------------------
532 def CreateSPICEFileList(Args
, SchemFileList
):
534 This fcn opens each .sch file found and loops through it.
535 While looping, it looks for SPICE files (typically lurking in lines like
536 "file=/path/to/spice/models/circuit.cir". When it finds a SPICE
537 file, it sticks it in the SPICEFileList.
538 The SPICE file names found are returned as absolute paths.
540 DebugSpew(Args
, "Now in CreateSPICEFIleList.")
541 SPICEFileList
= [] # List starts as empty
544 for SchemFileName
in SchemFileList
:
545 # Open file in user dir.
546 GschemFile
= open(Args
.UserDir
+"/"+os
.path
.basename(SchemFileName
), "r")
547 for Line
in GschemFile
.readlines():
548 if (re
.match('^file=', Line
)):
549 Match
= re
.match('(file=)(\S+)', Line
)
550 SPICEFile
= Match
.group(2)
551 # This needs to be more sophosticated
552 # SPICEFile = os.path.normpath(SPICEFile)
553 SPICEFile
= os
.path
.abspath(SPICEFile
)
554 DebugSpew(Args
, "Found "+SPICEFile
+" in schematic "+SchemFileName
)
556 # Next we need to make sure that this file is not already in the list.
557 if SPICEFile
in SPICEFileList
:
560 SPICEFileList
.append(SPICEFile
)
564 #---------------------------------------------------------------------------
565 def UpdateSchemFiles(Args
, SchemFileList
):
567 This fcn opens each .sch file found and loops through it.
568 It stuffs each file line found into a list of lines. While
569 looping, it looks for SPICE files (typically lurking in lines like
570 "file=/path/to/spice/models/circuit.cir". When it finds a SPICE
571 file, it substitutes the line found with "file=./gschem-files/circuit.cir".
572 After running through the file, it closes
573 the file, re-opens it as write-only, and outputs the changed file.
574 Yes, this operation could take place in CreateSPICEFileList, but I thought
575 it better conceptually & architecturally to split it off to a separate fcn.
577 DebugSpew(Args
, "Now in UpdateSchemFileList.")
580 for SchemFileName
in SchemFileList
:
581 # Open file in user dir.
582 GschemFile
= open(Args
.ScratchDir
+"/"+os
.path
.basename(SchemFileName
), "r")
584 Line
= GschemFile
.readline()
588 if (re
.match('^file=', Line
)):
589 Match
= re
.match('(file=)(\S+)', Line
)
590 SPICEFile
= Match
.group(2)
591 DebugSpew(Args
, "Found "+SPICEFile
+" in schematic "+SchemFileName
)
592 SPICEFile
= Args
.FileArchiveDir
+"/"+os
.path
.basename(SPICEFile
)
593 DebugSpew(Args
, "Updating line to point to "+SPICEFile
)
594 SavedLine
.append("file="+SPICEFile
+"\n")
596 SavedLine
.append(Line
)
599 # Now write out list in place of file.
600 GschemFile
= open(Args
.ScratchDir
+"/"+os
.path
.basename(SchemFileName
), "w")
601 for Line
in SavedLine
:
602 GschemFile
.write(Line
)
608 #---------------------------------------------------------------------------
609 def SaveSymbols(SymFileList
, LibraryFileList
, ArchiveDirectory
):
611 This fcn loops through all symbols in the list,
612 and copies the file into the local
615 DebugSpew(Args
, "Now in SaveSymbols.")
616 for SymFileName
in SymFileList
:
617 DebugSpew(Args
, "Saving symbol "+SymFileName
+" into archive "+ArchiveDirectory
)
618 os
.system("cp "+SymFileName
+" "+ArchiveDirectory
+"/"+os
.path
.basename(SymFileName
) )
621 #---------------------------------------------------------------------------
622 def SaveSPICEFiles(SPICEFileList
, ArchiveDirectory
):
624 This fcn loops through all SPICE files in the list, finds the corresponding
625 file somewhere in the directory tree, and then copies the file into the local
628 DebugSpew(Args
, "Now in SaveSPICEFiles.")
629 for SPICEFileName
in SPICEFileList
:
630 DebugSpew(Args
, "Saving SPICE file "+SPICEFileName
+" into archive "+ArchiveDirectory
)
631 os
.system("cp "+SPICEFileName
+" "+ArchiveDirectory
+"/"+os
.path
.basename(SPICEFileName
) )
635 #---------------------------------------------------------------------------
638 This fcn takes the gschemrc and updates it.
639 It runs through the file, and comments out any
640 occurance of (component-library. . . . Then it appends
641 a pointer to the local gschem-files directory
643 DebugSpew(Args
, "Now in UpdateRC.")
644 FileName
= os
.path
.basename(Args
.GschemRcFileName
)
646 # First run through the file, reading the lines and building a list
649 GschemRCFile
= open(FileName
, "r")
651 Line
= GschemRCFile
.readline()
655 if (re
.match('^\(component-library', Line
)):
656 SavedLine
.append(";; "+Line
) # Comment out any (component-library lines found
658 SavedLine
.append(Line
)
662 # Now write out list in place of file.
663 GschemRCFile
= open(FileName
, "w")
664 for Line
in SavedLine
:
665 GschemRCFile
.write(Line
)
667 # Write pointer to new lib into file
668 GschemRCFile
.write("(component-library \"./"+Args
.FileArchiveDir
+"\")\n")
674 #---------------------------------------------------------------------------
675 def IsSimpleFile(File
):
677 This fcn returns 1 if file is simple file name ("gschemrc"), or is a
678 simple directory name ("gschem-files"). It returns 0 if File is a
679 compound file name ("gschem-files/symbol-1.sym").
681 if (os
.path
.basename(File
) == File
):
682 return 1 # Simple file
683 elif (os
.path
.isdir(File
)):
689 ############################################################################
690 # Body of archiver lives here #
691 ############################################################################
694 This is the main archiver. Program algorithm is documented above. Primary
695 data structures are a bunch of lists holding various file names.
697 # First check that ScratchDir is writable by the user. We will CD there
698 # to do real work later.
700 TestFile
= open(Args
.ScratchDir
+"/gschem_test", "w")
702 print("Can't work in "+Args
.ScratchDir
+" directory. Check that you have write permission there.")
706 os
.remove(Args
.ScratchDir
+"/gschem_test")
708 # Create list of files (and directories) to stick into archive. Returned paths point
709 # to the absolute paths of the files.
710 ArchiveFileList
= CreateArchiveFileList(Args
)
713 # print "ArchiveFileList = ",
714 # print ArchiveFileList
716 # Create list of paths to various library files. Returned paths are absolute path names
717 LibraryPathList
= GetLibraryPath(Args
)
720 # print "LibraryPathList = ",
721 # print LibraryPathList
723 # Create list of schematic files to open and search. Returned paths
724 # give only the base name (i.e. no path)
725 SchemFileList
= CreateSchemFileList(Args
, ArchiveFileList
)
728 # print "SchemFileList = ",
729 # print SchemFileList
731 # Now run through SchemFileList and create list of symbols. Symbols are returned
732 # with only base file name (i.e. no path).
733 SymbolFileList
= CreateSymbolFileList(SchemFileList
, LibraryPathList
)
736 # print "SymbolFileList = ",
737 # print SymbolFileList
739 # Now run through SchemFileList and create list of pointers to spice files
740 # ("file" attributes). SPICEFiles are returned using absolute paths.
741 SPICEFileList
= CreateSPICEFileList(Args
, SchemFileList
)
744 # print "SPICEFileList = ",
745 # print SPICEFileList
747 # Now cd into /tmp dir and copy all files over to /tmp directory for processing.
748 os
.chdir(Args
.ScratchDir
)
750 DebugSpew(Args
, "Cd into "+Args
.ScratchDir
+" for remainder of work.")
751 for File
in ArchiveFileList
:
752 if (os
.path
.dirname(File
) == Args
.UserDir
):
753 os
.system("cp "+File
+" "+Args
.ScratchDir
)
755 # Now run through SchemFileList and update .sch file by stuffing names
756 # of SPICE files into them. Save the resulting .sch files in the /tmp directory.
757 UpdateSchemFiles(Args
,SchemFileList
)
759 # Open gschem-files directory and stick symbol & SPICE files into into it
761 Dir
= NormalizePath(Args
.ScratchDir
, Args
.FileArchiveDir
)
763 except: # Directory exists.
764 os
.system("rm -fR "+Dir
) # Remove contents of old dir
765 os
.mkdir(Dir
) # Replace with new dir.
767 SaveSymbols(SymbolFileList
, LibraryPathList
, Dir
)
768 SaveSPICEFiles(SPICEFileList
, Dir
)
770 # Now create tar file. We copy remaining files over to /tmp, and then tar them
771 # all up using a local, relative file prefix.
773 # Create string of files to archive
775 for File
in ArchiveFileList
:
776 # if (os.path.dirname(File) == Args.UserDir):
777 # os.system("cp "+File+" "+Args.ScratchDir)
778 ArchiveString
= ArchiveString
+" "+os
.path
.basename(File
)
780 DebugSpew(Args
, "Files to archive: "+ArchiveString
)
782 # Update copy of gschemrc
785 DebugSpew(Args
, "Creating archive in "+Args
.ScratchDir
+" directory.")
787 # Now use this in tar command.
788 os
.system("tar -cf "+Args
.OutputFileNameBase
+".tar "+ArchiveString
)
789 os
.system("gzip "+Args
.OutputFileNameBase
+".tar")
791 # Now try to move completed archive back to user directory.
792 DebugSpew(Args
, "Moving archive into local directory.")
794 os
.stat(Args
.UserDir
+"/"+Args
.OutputFileName
)
795 except OSError: # archive is not in user directory yet, no need to force it.
796 os
.system("mv "+Args
.OutputFileName
+" "+Args
.UserDir
)
797 else: # Directory already exists
798 Input
= raw_input(Args
.UserDir
+"/"+Args
.OutputFileName
+" already exists. Overwrite? [y/N] ")
799 if ( (len(Input
) == 0) or (Input
[0] != "y") ):
800 print("Preserving existing archive in local directory.")
801 print("Your new archive lives in "+Args
.ScratchDir
+"/"+Args
.OutputFileName
)
803 os
.system("rm -fR "+Args
.UserDir
+"/"+Args
.OutputFileName
) # Remove old archive
804 os
.system("mv "+Args
.OutputFileName
+" "+Args
.UserDir
)
805 print("gEDA archive "+Args
.UserDir
+"/"+Args
.OutputFileName
+" created successfully!")
807 # Clean up remaining mess
808 os
.system("rm -fR "+ArchiveString
)
809 os
.chdir(Args
.UserDir
)
811 return # End of fcn . . .
813 ############################################################################
814 # Body of extracter lives here #
815 ############################################################################
818 This fcn extracts the archive. It tries to do it very carefully, and won't
819 overwrite anything you don't want it to. Algorithm:
820 1. copy archive file into /tmp
822 3. Extract files indivdually, and check that each one is not present in the
823 destination dir before moving it.
825 if (len(Args
.CmdLineFileList
) == 0):
826 print("Must specify a filename for extraction.")
830 for FileName
in Args
.CmdLineFileList
:
831 DebugSpew(Args
, "Trying to extract archive "+FileName
+".")
836 print("File "+FileName
+" doesn't exist. Ignoring")
840 os
.system("cp -f "+FileName
+" "+Args
.ScratchDir
)
842 print("Can't work in the "+Args
.ScratchDir
+" directory. Check that you have write permisison there.")
845 os
.chdir(Args
.ScratchDir
)
847 # Change name of file so it can be gunziped.
848 if not CheckFilename(FileName
):
850 Error -- the file suffix is not \".tar.gz\"; garchive can't do extraction.
851 If this archive was created using garchive, you can rename it using
852 .tar.gz as suffix and try again. Otherwise, just gunzip and tar -xvf
857 # Now gunzip the file, then change File name to reflect new status (.tar)
858 os
.system("gunzip -f "+FileName
)
859 NewFileName
= re
.sub('\.gz', '', FileName
)
861 # Get list of files in archive. Then open up archive
862 ReturnString
= commands
.getoutput("tar -t -f "+NewFileName
)
863 FileList
= re
.split('\s+', ReturnString
)
865 for File
in FileList
:
866 DebugSpew(Args
, "Extracting "+File
)
867 os
.system("tar -f "+NewFileName
+" -x "+File
)
869 # We need to treat directories carefully. For each file, check
870 # if it is a simple file, a directory name, or a compound file.
871 for File
in FileList
:
872 if (IsSimpleFile(File
)):
874 os
.stat(Args
.UserDir
+"/"+File
)
876 os
.system("mv "+File
+" "+Args
.UserDir
)
878 Input
= raw_input(Args
.UserDir
+"/"+File
+" already exists. Overwrite? [yN] ")
879 if ( (len(Input
) == 0) or (Input
[0] != "y") ):
880 print("Preserving existing "+File
+" in local directory.")
882 os
.system("rm -fR "+Args
.UserDir
+"/"+File
)
883 os
.system("mv -f "+File
+" "+Args
.UserDir
)
885 # Now clean up /tmp directory
886 os
.system("rm -fR "+NewFileName
)
887 os
.system("rm -fR "+FileName
)
888 os
.chdir(Args
.UserDir
)
890 return # End of fcn . . . . .
892 ############################################################################
893 ############################################################################
894 # Main prog begins here #
895 ############################################################################
896 ############################################################################
897 # First get and parse command line args
898 Args
= CmdLineArgs() # Creates Args object holding command line args info.
900 if Args
.ProgramMode
== "archive":
903 elif Args
.ProgramMode
== "extract":
907 raise RuntimeError("Unknown program mode found.")
909 # That's it -- very simple!!