[RFC] handle paths in a saner way

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

[RFC] handle paths in a saner way

Paolo Bonzini
I started implementing the --kernel-directory and --image-directory
options, but I got carried away and ended up reimplementing a lot of the
startup sequence, and in particular the way kernel files are looked up.
  This had interesting ramifications.

The changes can be summed up like this:

- the `~/.stinit' and `~/.stpre' files are now named `~/.st/init.st' and
`~/.st/pre.st'

- files requested with the `-K' command-line option are sought for in
the `~/.st' directory too

- kernel files may be overridden by placing them in `.st/kernel'; they
will be used when you do `gst -i' but you cannot write to
`/usr/local/share/smalltalk'

- a site-wide customization file can be placed in
`/usr/local/share/smalltalk/site-pre.st'.  It will be loaded whenever
users create images with `gst -i', before the snapshot and before the
`~/.st/pre.st' file.

- the kernel path is stored in the image when it's created; it's not
changed when the image is loaded.  In addition, `Directory systemKernel'
and `Directory localKernel' are not used anymore, and just return the
same as `Directory kernel'.

- Smalltalk programs have access to the aforementioned `~/.st' directory
as `Directory userKernel' (name subject to change).  A `packages.xml'
file can be put in the directory too -- I like this a lot.


Now, apart from scrutinizing the code (which I'll appreciate), I'm
looking for:

- alternative names for `Directory userKernel', which is really `~/.st';
  I thought of `Directory userRoot' but I don't really like it;

- if you don't like the semantics (details are in the manual, in the
Startup Sequence node), suggestions on how to improve them;

- whether root (or any other user who can write to /usr/local/share)
should be forbidden from having a ~/.st directory;

- whether `~/.st/init.st' makes sense at all; I'm inclined to remove it;



All this will obviously be in 2.4/3.0 only.

Paolo

2007-02-06  Paolo Bonzini  <[hidden email]>

        * kernel/Directory.st: Add #kernel and #userKernel, deprecate
        #systemKernel and #localKernel.
        * kernel/VFS.st: Adjust.
        * kernel/PkgLoader.st: Adjust.
        * kernel/SysDict.st: Add #imageLocal.

        * libgst/dict.c: Remove KernelFileLocalPath.  Don't touch
        KernelFilePath on reload.  Export ImageLocal and KernelFileUserPath.
        * libgst/lib.c: Add --image-directory and --kernel-directory.
        Add a struct loaded_file used to store files given on
        the command line.  Find path of user init/user pre/site
        pre files in init_paths, delete load_user_init_file and
        load_user_pre_image_file.  Call init_paths after parse_args.
        Rewrite find_kernel_file, place kernel override files
        in ~/.st too (if one needs per-image overrides they can
        use --kernel-directory).  Remove some variables that are
        now unused.  Simplify ok_to_load_binary as the new semantics
        remove the need for some checks.  Export the path to ~/.st in
        _gst_user_kernel_path, and is_local_image.
        * libgst/lib.h: Export _gst_user_kernel_path and _gst_is_local_image.

--- orig/Makefile.am
+++ mod/Makefile.am
@@ -127,9 +127,8 @@ gsticon.o: gsticon.ico
  echo ProgramIcon ICON `cygpath -w gsticon.ico` | windres -o gsticon.o
 
 gst.im: $(bin_PROGRAMS) $(srcdir)/kernel/stamp-classes
- SMALLTALK_KERNEL="`cd $(srcdir)/kernel; pwd`" \
- SMALLTALK_IMAGE="`pwd`" \
-  ./gst -iQ /dev/null
+ ./gst --kernel-dir="@abs_top_srcdir@/kernel" \
+  --image-dir="@abs_top_builddir@" -iQ /dev/null
 
 all-local:
 


--- orig/NEWS
+++ mod/NEWS
@@ -2,17 +2,35 @@ List of user-visible changes in GNU Smal
 
 NEWS FROM 2.3.2 TO 2.4
 
-o   Startup time and quit time were improved widely (the time for running
-    a simple "Hello, World" program is about one fifth of 2.3.x).
+o   A different startup sequence is used which improves the possibility to
+    customize GNU Smalltalk, both site-wide and per-user.  The details are
+    in the manual, the main changes are these: the `.stinit' and `.stpre'
+    files are now named `.st/init.st' and `.st/pre.st'; files requested
+    with the `-K' command-line option are sought for in the `.st' directory
+    too (in the home directory); kernel files may be overridden by placing
+    them in `.st/kernel'; a site-wide customization file can be placed
+    in `/usr/local/share/smalltalk/site-pre.st'.
+
+    The kernel path is stored in the image and not changed when the image
+    is loaded.  In addition, `Directory systemKernel' and `Directory
+    localKernel' are not used anymore, and just return the same as
+    `Directory kernel'.
+
+    Finally, Smalltalk programs have access to the aforementioned `.st'
+    directory as `Directory userKernel' (name subject to change).  A
+    `packages.xml' file can be put there.
 
 o   Directory entries are passed to #allFilesMatching:do:'s block argument
     if they match aPattern.  As before, the function descends in all the
     directories, even those that do not match aPattern.
 
-o   The image is loaded using copy-on-write memory mapped files.  This means
-    that as long as a loaded object is not touched, the operating system
-    will map it to the same physical memory, for different copies of
-    the GNU Smalltalk virtual machine that loaded the same image.
+o   Image load uses copy-on-write memory mapped files.  This means that, as
+    long as a loaded object is not touched, the operating system will map
+    it to the same physical memory, for different copies of the GNU Smalltalk
+    virtual machine that loaded the same image.
+
+o   Startup time and quit time were improved widely (the time for running
+    a simple "Hello, World" program is about one fifth of 2.3.x).
 
 -----------------------------------------------------------------------------
 


--- orig/doc/Makefile.am
+++ mod/doc/Makefile.am
@@ -41,42 +41,26 @@ PUBLISHED_NAMESPACES = Smalltalk SystemE
 
 $(srcdir)/blox.texi: $(top_srcdir)/blox-tk/stamp-classes
  rm -f $(srcdir)/blox.texi
- builddir=`pwd`; gst=$$builddir/../gst; gst_im=$$builddir/../gst.im; \
- cd $(srcdir) && \
-  $$gst -I $$gst_im -f ../scripts/GenLibDoc.st \
-    BLOX BloxTK blox.texi Blox.st
+ cd $(srcdir) && @abs_top_builddir@/gst -I @abs_top_builddir@/gst.im \
+    -f ../scripts/GenLibDoc.st BLOX BloxTK blox.texi Blox.st
  test -f $(srcdir)/blox.texi && touch $(srcdir)/gst-libs.texi
 
 $(srcdir)/tcp.texi: $(top_srcdir)/tcp/stamp-classes
  rm -f $(srcdir)/tcp.texi
- builddir=`pwd`; gst=$$builddir/../gst; gst_im=$$builddir/../gst.im; \
- cd $(srcdir) && \
-  $$gst -I $$gst_im -f ../scripts/GenLibDoc.st \
-    TCP TCP tcp.texi TCP.st
+ cd $(srcdir) && @abs_top_builddir@/gst -I @abs_top_builddir@/gst.im \
+    -f ../scripts/GenLibDoc.st TCP TCP tcp.texi TCP.st
  test -f $(srcdir)/tcp.texi && touch $(srcdir)/gst-libs.texi
 
 $(srcdir)/i18n.texi: $(top_srcdir)/i18n/stamp-classes
  rm -f $(srcdir)/i18n.texi
- builddir=`pwd`; gst=$$builddir/../gst; gst_im=$$builddir/../gst.im; \
- cd $(srcdir) && \
-  $$gst -I $$gst_im -f ../scripts/GenLibDoc.st \
-    I18N I18N i18n.texi Load.st Collation.st
+ cd $(srcdir) && @abs_top_builddir@/gst -I @abs_top_builddir@/gst.im \
+    -f ../scripts/GenLibDoc.st I18N I18N i18n.texi Load.st Collation.st
  test -f $(srcdir)/i18n.texi && touch $(srcdir)/gst-libs.texi
 
-$(srcdir)/regex.texi: $(top_srcdir)/examples/regex.st
- rm -f $(srcdir)/regex.texi
- builddir=`pwd`; gst=$$builddir/../gst; gst_im=$$builddir/../gst.im; \
- cd $(srcdir) && \
-  $$gst -I $$gst_im -f ../scripts/GenLibDoc.st \
-    Regex Regex regex.texi
- test -f $(srcdir)/regex.texi && touch $(srcdir)/gst-libs.texi
-
 $(srcdir)/classes.texi: $(top_srcdir)/kernel/stamp-classes
  rm -f $(srcdir)/classes.texi
- builddir=`pwd`; gst=$$builddir/../gst; gst_im=$$builddir/../gst.im; \
- cd $(srcdir) && \
-  $$gst -I $$gst_im -f ../scripts/GenBaseDoc.st \
-  $(PUBLISHED_NAMESPACES)
+ cd $(srcdir) && @abs_top_builddir@/gst -I @abs_top_builddir@/gst.im \
+    -f ../scripts/GenBaseDoc.st $(PUBLISHED_NAMESPACES)
  test -f $(srcdir)/classes.texi && touch $(srcdir)/gst-base.texi
 
 # In TeX output, having colons in index entries looks pretty, but


--- orig/doc/gst.texi
+++ mod/doc/gst.texi
@@ -302,7 +297,7 @@ names, but their effect is as if they we
 various flags are interpreted as follows:
 
 @table @option
-@item -a --smalltalk
+@item -a --smalltalk-args
 Used to make arguments available to Smalltalk code.  The C option parser
 discards everything after the parameter including @option{-a}, while
 Smalltalk code can get it sending the @code{arguments} message to the
@@ -362,6 +357,20 @@ Like the -e flag, but includes all byte
 occur during the loading of the kernel method definition files, or
 during the loading and execution of user files.
 
+@item --image-directory
+Specify the directory from which the image file will be loaded.
+
+@item --kernel-directory
+Specify the directory from which the kernel files will be loaded.
+
+@item -K --kernel-file
+Specify a file to be loaded from the system kernel path.  These are
+files that are usually distributed and installed together with GNU
+Smalltalk, or that are placed under the @file{.st/kernel}
+  subdirectory in the user's home directory@footnote{The directory is
+  called @file{_st/kernel} under MS-DOS.  Under OSes that don't use home
+  directories, it is looked for in the current directory.}.
+
 @item -f --file
 This special flag is designed to prepare Smalltalk programs that can
 be invoked from the Unix shell.  The following two command lines are
@@ -452,54 +461,70 @@ executed).
 @node Operation
 @section Startup sequence
 
+@strong{Caveat}: @emph{The startup sequence is pretty complicated.  If you
+are not interested in its customization, you can jump to the paragraph
+beginning with @emph{Finally}.}
+
 When @gst{} is invoked, the first thing it does is choosing two paths,
-respectively the ``image path'' and the ``kernel path''.  the image path
-is set to the value of the @env{SMALLTALK_IMAGE} environment variable
-(if it is defined); if @env{SMALLTALK_IMAGE} is not defined, Smalltalk
-will try the path compiled in the binary (usually, under Unix systems,
-@file{/usr/local/share/gnu-smalltalk} or a similar data file path) and
-then the current directory.
-
-The ``kernel path'' directory in which to look for each of the kernel
-method definition files.  There are only two possibilities in this case:
-the directory pointed to by @env{SMALLTALK_KERNEL} if it is defined,
-and a subdirectory named @file{kernel} in the current directory.
-However, kernel files are not required to be in this directory:
-Smalltalk also knows about a system default location for kernel files,
-which is compiled in the binary (usually, under Unix systems,
-@file{/usr/local/share/gnu-smalltalk/kernel} or a similar data file
-path), and which is used for kernel files not found in the directory
-chosen as above.
+respectively the ``image path'' and the ``kernel path''.  The image path
+is set by considering these paths in succession:
+@itemize
+@item the argument to the @option{--image-directory} option or, if none
+  is specified, the value of the @env{SMALLTALK_IMAGE} environment variable
+  (if it is defined);
+@item the path compiled in the binary (usually, under Unix systems,
+  @file{/usr/local/share/smalltalk} or a similar data file path);
+@item the current directory.  The current directory is also used if
+  you use @option{-i} but you cannot write to the image directory.
+@end itemize
 
-Then, if the @option{-i} flag is not used, Smalltalk tries to find a saved
+The ``kernel path'' is the directory in which to look for each of the kernel
+method definition files.  The possibilities in this case are:
+@itemize
+@item the argument to the @option{--kernel-directory} option or, if none
+  is specified, the value of the @env{SMALLTALK_KERNEL} environment variable
+  (if it is defined);
+@item a subdirectory of the image path named @file{kernel} in the current
+  directory.
+@end itemize
+
+Unless the @option{-i} flag is used, GNU Smalltalk first tries to find a saved
 binary image file in the image path.  If this is found, it is checked to
-be compatible with the current version of Smalltalk and with the current
-system; Smalltalk is able to load an image created on a system with the
-same @code{sizeof(long)} but different endianness (for example, a 68k
+be compatible with the current version of the virtual machine and with the
+current system; GNU Smalltalk is able to load an image created on a system with
+the same pointer size but different endianness (for example, a PowerPC
 image on an x86), but not an image created on a system with different
-@code{sizeof(long)} like an Alpha image on an x86.  Finally, if the
+pointer sizes like an x86-64 image on an x86.  Finally, if the
 images are compatible, it compares the write dates of all of the kernel
 method definition files against the write date of the binary image file.
 
 If the image is not found, is incompatible, or older than any of the
-kernel files, a new image has to be created.  The set of files that make
-up the kernel is loaded, one at a time.  The list can be found in
-@file{libgst/lib.c}, in the @code{standardFiles} variable.  If the image
-lies in the current directory, or if at least a kernel file was found
-outside of the system default path, a user-dependant
-@file{.stpre}@footnote{ The file is called @file{_stpre} under MS-DOS
-and @file{.gstpre} on the Atari ST.  Under OSes that don't use home
-directories it is looked for in the current directory.}
+kernel files, a new image has to be created.  If the previously found
+image path is not writeable, GNU Smalltalk reverts to the current
+directory.  The set of files that make up the kernel is loaded,
+one at a time.  The list can be found in @file{libgst/lib.c}, in the
+@code{standard_files} variable.  Before saving a local
+image a site-dependent @file{site-pre.st} file is loaded, which should
+be placed in the parent directory of the kernel directory.
+
+If the image is created in the current directory, the user can override
+kernel files by placing their own copies under the @file{.st/kernel}
+subdirectory in the user's home directory@footnote{The directory is
+  called @file{_st/kernel} under MS-DOS.  Under OSes that don't use home
+  directories, it is looked for in the current directory.}.  In this case,
+additionally, GNU Smalltalk will load a user-dependant @file{.st/pre.st}
+file@footnote{The directory is called @file{_st/pre.st} under MS-DOS and
+  again, under OSes that don't use home directories it is looked for as
+  @file{pre.st} in the current directory.}.
 
 At this point, independent of whether the binary image file was loaded
-or created, the @code{initialize} event is sent to the dependants of the
-special class @code{ObjectMemory} (@pxref{Memory access}).  After the
-initialization blocks have been executed, the user initialization file
-@file{.stinit} is loaded if found in the user's home
-directory@footnote{The same considerations made above hold here too.
-The file is called @file{_stinit} under MS-DOS and @file{.gstinit} on
-the Atari ST, and is looked for in the current directory under OSes that
-don't use home directories.}.
+or created, the @code{returnFromSnapshot} event is sent to the dependants of
+the special class @code{ObjectMemory} (@pxref{Memory access}).  After these
+finish executing their initialization code, the user file @file{.st/init.st} is
+loaded if found in the user's home directory@footnote{The same considerations
+  made above hold here too.  The file is called @file{_st/init.st} under MS-DOS,
+  and is looked for in the current directory under OSes that don't use home
+  directories.}.
 
 Finally, if there were any files specified on the command line, they are
 loaded, otherwise standard input is read and executed until an EOF is
@@ -1501,16 +1522,27 @@ dynamic linking will result in an error.
 
 Thanks to Andreas Klimas' insight, @gst{} now includes a
 powerful packaging system which allows one to file in components
-(@dfn{goodies} in Smalltalk's very folkloristic terminology)
-without caring of whether they need other goodies to be loaded.
+(often called @dfn{goodies} in Smalltalk's very folkloristic
+terminology) without caring of whether they need other goodies to be
+loaded first.
 
 The packaging system is implemented by a Smalltalk class,
 @code{PackageLoader}, which looks for information about packages in
-the XML file named (guess what) @file{packages.xml}, in the current image
-directory. There are two ways to load something using the packaging
-system. The first way is to use the PackageLoader's
-@code{fileInPackage:} and @code{fileInPackages:} methods.
-For example:
+the XML file named (guess what) @file{packages.xml}, in one of three
+places:
+@itemize
+@item the kernel directory's parent directory; this is where
+  an installed @file{packages.xml} resides, in a system-wide data
+  directory such as @file{/usr/local/share/smalltalk};
+@item in the file @file{.st/packages.xml} hosts per-user packages;
+@item finally, there can be a @file{packages.xml} in the current
+  image directory.
+@end itemize
+
+There are two ways to load something using the packaging system. The
+first way is to use the PackageLoader's @code{fileInPackage:} and
+@code{fileInPackages:} methods.  For example:
+
 @example
     PackageLoader fileInPackages: #('Blox' 'Browser').
     PackageLoader fileInPackage: 'Compiler'.


--- orig/kernel/Directory.st
+++ mod/kernel/Directory.st
@@ -70,14 +70,20 @@ module
 !
 
 systemKernel
-    "Answer the path to the GNU Smalltalk kernel's Smalltalk source files"
-    ^KernelFileSystemPath
+    "Answer the path to the GNU Smalltalk kernel's Smalltalk source files.
+     Same as `Directory kernel' since GNU Smalltalk 2.4."
+    ^self kernel
 !
 
 localKernel
-    "Answer the path in which a local version of the GNU Smalltalk kernel's
-     Smalltalk source files were found"
-    ^KernelFileLocalPath
+    "Answer the path to the GNU Smalltalk kernel's Smalltalk source files.
+     Same as `Directory kernel' since GNU Smalltalk 2.4."
+    ^self kernel
+!
+
+userKernel
+    "Answer the path to user-customized source files for GNU Smalltalk kernel's."
+    ^KernelFileUserPath
 !
 
 temporary


--- orig/kernel/PkgLoader.st
+++ mod/kernel/PkgLoader.st
@@ -384,15 +384,15 @@ flush
 
 refreshDependencies
     "Reload the `packages.xml' file in the image and kernel directories.
-     The three possible places are 1) the system kernel directory's parent
-     directory, 2) the local kernel directory's parent directory, 3) the
+     The three possible places are 1) the kernel directory's parent
+     directory, 2) the `.st' subdirectory of the user's home directory, 3) the
      local image directory (in order of decreasing priority).
 
-     For a packages.xml found in the system kernel directory's parent
+     For a packages.xml found in the kernel directory's parent
      directory, all three directories are searched.  For a packages.xml
-     found in the local kernel directory's parent directory, only
-     directories 2 and 3 are searched.  For a packages.xml directory in
-     the local image directory, instead, only directory 3 is searched."
+     found in the `.st' subdirectory, only directories 2 and 3 are
+     searched.  For a packages.xml directory in the local image directory,
+     finally, only directory 3 is searched."
     | state |
     LoadDate isNil ifFalse: [
  self stillValid ifTrue: [ ^self ]
@@ -400,14 +400,23 @@ refreshDependencies
 
     LoadDate := Date dateAndTimeNow.
     Packages := LookupTable new.
-    self
- processPackageFile: self systemPackageFileName
- baseDirectories: {
-    Directory systemKernel, '/..'. Directory kernel, '/..'.
-    Directory image }.
-    self
- processPackageFile: self packageFileName
- baseDirectories: { Directory kernel, '/..'. Directory image }.
+    Smalltalk imageLocal
+ ifTrue: [
+    self
+ processPackageFile: self packageFileName
+ baseDirectories: {
+    Directory image. Directory userKernel.
+    Directory kernel, '/..' }.
+    self
+ processPackageFile: self userPackageFileName
+ baseDirectories: { Directory image. Directory userKernel }.
+ ]
+ ifFalse: [
+    self
+ processPackageFile: self packageFileName
+ baseDirectories: { Directory image. Directory kernel, '/..' }.
+ ].
+
     self
  processPackageFile: self localPackageFileName
  baseDirectories: { Directory image }.
@@ -507,14 +516,14 @@ isLoadable: feature
 
 !PackageLoader class methodsFor: 'private - packages file'!
 
-systemPackageFileName
-    ^Directory systemKernel, '/../packages.xml'
-!
-
 packageFileName
     ^Directory kernel, '/../packages.xml'
 !
 
+userPackageFileName
+    ^Directory userKernel, '/packages.xml'
+!
+
 localPackageFileName
     ^Directory image, '/packages.xml'
 !
@@ -603,7 +612,7 @@ processPackageFile: fileName baseDirecto
 !
 
 stillValid
-    ^{ self packageFileName. self localPackageFileName. self systemPackageFileName }
+    ^{ self packageFileName. self localPackageFileName. self userPackageFileName }
  allSatisfy: [ :name || file |
     file := File name: name.
     file exists not or: [ file lastModifyTime < LoadDate ]


--- orig/kernel/SysDict.st
+++ mod/kernel/SysDict.st
@@ -131,6 +131,11 @@ removeFeature: aFeature
     Features remove: aFeature ifAbsent: [ ]
 !
 
+imageLocal
+    "Answer whether the image is a user's custom image"
+    ^ImageLocal
+!
+
 version
     "Answer the current version of the GNU Smalltalk environment"
     ^Version


--- orig/kernel/VFS.st
+++ mod/kernel/VFS.st
@@ -773,17 +773,20 @@ updateMember: anArchiveMemberHandler
 
 fileSystems
     "Answer the virtual file systems that can be processed by this subclass.
-     These are given by the names of the executable files in the vfs
+     These are given by the names of the executable files in the `vfs'
      subdirectory of the image directory, of the parent of the kernel
-     directory and of the parent of the system kernel directory."
+     directory and (if the image is not the global installed image)
+     of the `.st' directory in the home directory."
     ActivePaths := WeakValueLookupTable new.
     FileTypes := LookupTable new.
     [ self fileSystemsIn: Directory kernel, '/../vfs' ]
  on: Error do: [ :ex | ex return ].
     [ self fileSystemsIn: Directory image, '/vfs' ]
  on: Error do: [ :ex | ex return ].
-    [ self fileSystemsIn: Directory systemKernel, '/../vfs' ]
- on: Error do: [ :ex | ex return ].
+    Smalltalk imageLocal ifTrue: [
+        [ self fileSystemsIn: Directory userKernel, '/vfs' ]
+    on: Error do: [ :ex | ex return ].
+    ].
 
     ^FileTypes keys asSet!
 


--- orig/libgst/dict.c
+++ mod/libgst/dict.c
@@ -816,9 +816,6 @@ _gst_init_dictionary (void)
 
   create_classes_pass2 (class_info, sizeof (class_info) / sizeof (class_info[0]));
 
-  add_smalltalk ("KernelFilePath",
- _gst_string_new (_gst_kernel_file_path));
-
   init_runtime_objects ();
   _gst_tenure_all_survivors ();
 }
@@ -1024,11 +1021,14 @@ init_smalltalk_dictionary (void)
 
   add_smalltalk ("Smalltalk", _gst_smalltalk_dictionary);
   add_smalltalk ("Version", _gst_string_new (fullVersionString));
+  add_smalltalk ("KernelFilePath", _gst_string_new (_gst_kernel_file_path));
   add_smalltalk ("CObjectType", _gst_c_object_type_ctype);
   add_smalltalk ("KernelInitialized", _gst_false_oop);
   add_smalltalk ("SymbolTable", _gst_symbol_table);
   add_smalltalk ("Processor", _gst_processor_oop);
   add_smalltalk ("Features", featuresArrayOOP);
+  add_smalltalk ("ImageLocal",
+ _gst_is_local_image ? _gst_true_oop : _gst_false_oop);
 
   /* Add subspaces */
   add_smalltalk ("CSymbols",
@@ -1061,10 +1061,8 @@ add_smalltalk (const char *globalName,
 void
 init_runtime_objects (void)
 {
-  add_smalltalk ("KernelFileSystemPath", _gst_string_new (KERNEL_PATH));
+  add_smalltalk ("KernelFileUserPath", _gst_string_new (_gst_user_kernel_path));
   add_smalltalk ("ModulePath", _gst_string_new (MODULE_PATH));
-  add_smalltalk ("KernelFileLocalPath",
- _gst_string_new (_gst_kernel_file_path));
   add_smalltalk ("ImageFilePath",
  _gst_string_new (_gst_image_file_path));
   add_smalltalk ("ImageFileName",


--- orig/libgst/lib.c
+++ mod/libgst/lib.c
@@ -65,13 +65,15 @@
 /* #define DEBUG_GETOPT */
 
 #ifdef MSDOS
-#define INIT_FILE_NAME "_stinit"
-#define PRE_IMAGE_FILE_NAME "_stpre"
+#define LOCAL_BASE_DIR_NAME "_st"
 #else
-#define INIT_FILE_NAME ".stinit"
-#define PRE_IMAGE_FILE_NAME ".stpre"
+#define LOCAL_BASE_DIR_NAME ".st"
 #endif
 
+#define USER_INIT_FILE_NAME "init.st"
+#define USER_PRE_IMAGE_FILE_NAME "pre.st"
+#define LOCAL_KERNEL_DIR_NAME "kernel"
+#define SITE_PRE_IMAGE_FILE_NAME "site-pre.st"
 
 
 
@@ -127,8 +129,11 @@ static const char copyright_and_legal_st
   "\nUsing default kernel path: %s" "\nUsing default image path: %s"
   "\n";
 
+#define OPT_KERNEL_DIR 2
+#define OPT_IMAGE_DIR 3
+
 static const struct option long_options[] = {
-  {"smalltalk", 0, 0, 'a'},
+  {"smalltalk-args", 0, 0, 'a'},
   {"core-dump", 0, 0, 'c'},
   {"declaration-trace-user", 0, 0, 'd'},
   {"declaration-trace-all", 0, 0, 'D'},
@@ -137,6 +142,8 @@ static const struct option long_options[
   {"execution-trace-all", 0, 0, 'E'},
 #endif
   {"file", 0, 0, 'f'},
+  {"kernel-directory", 1, 0, OPT_KERNEL_DIR},
+  {"image-directory", 1, 0, OPT_IMAGE_DIR},
   {"no-gc-message", 0, 0, 'g'},
   {"help", 0, 0, 'H'},
   {"rebuild-image", 0, 0, 'i'},
@@ -152,6 +159,14 @@ static const struct option long_options[
   {"verbose", 0, 0, 'V'},
   {NULL, 0, 0, 0}
 };
+
+struct loaded_file {
+  mst_Boolean kernel_path;
+  const char *file_name;
+};
+
+static struct loaded_file *loaded_files;
+int n_loaded_files;
 
 
 /* When true, this flag suppresses the printing of execution-related
@@ -165,6 +180,13 @@ int _gst_verbosity = 2;
 const char *_gst_kernel_file_path = NULL;
 const char *_gst_image_file_path = NULL;
 
+/* The ".st" directory, in the current directory or in the user's
+   home directory.  */
+const char *_gst_user_kernel_path;
+
+/* Whether the image is global or per-user.  */
+mst_Boolean _gst_is_local_image;
+
 /* This is the name of the binary image to load.  If it is not NULL after the
    command line is parsed, the checking of the dates of the kernel source files
    against the image file date is overridden.  If it is NULL, it is set to
@@ -217,27 +239,19 @@ static void process_stdin ();
    kernel file is found.  */
 static mst_Boolean ok_to_load_binary (void);
 
-/* Attempts to find a viable kernel Smalltalk file (.st file).  First
-   tries the current directory to allow for overriding installed kernel
-   files.  If that isn't found, the full path name of the installed kernel
-   file is stored in fullFileName.  Note that the directory part of the
-   kernel file name in this second case can be overridden by defining the
-   SMALLTALK_KERNEL environment variable to be the directory that should
-   serve as the kernel directory instead of the installed one.
+/* Attempts to find a viable Smalltalk file for user-level customization.
+   FILENAME is a simple file name, sans directory; the file name to use
+   for the particular file is returned, or NULL if it is not found.  */
+static char *find_user_file (const char *fileName);
 
+/* Attempts to find a viable kernel Smalltalk file (.st file).
    FILENAME is a simple file name, sans directory; the file name to use
-   for the particular kernel file is returned in the FULLFILENAME variable
-   in this variable (which must be a string large enough for any file name).
-   If there is a file in the current directory with name FILENAME, that is
+   for the particular kernel file is returned.
+   If there is a file in the .stkernel directory with name FILENAME, that is
    returned; otherwise the kernel path is prepended to FILENAME (separated
-   by a slash, of course) and that is stored in the string pointed to by
-   FULLFILENAME.
-
-   Returns true if the kernel file is found in the local directory,
-   and false if the file was found using the default path.
- */
-static mst_Boolean find_kernel_file (const char *fileName,
-     char *fullFileName);
+   by a slash, of course) and that is stored in the string that is returned.  */
+static char *find_kernel_file (const char *fileName, const char *systemPrefix,
+       const char *userDir);
 
 /* Loads the kernel Smalltalk files.  It uses a vector of file names,
    and loads each file individually.  To provide for greater
@@ -258,25 +272,17 @@ static void init_paths (void);
 static int parse_args (int argc,
        const char **argv);
 
-/* These functions load the per-user customization files, respectively
+/* Path names for the per-user customization files, respectively
    .stinit (loaded at every startup) and .stpre (loaded before a local
    image is saved.  */
-static void load_user_init_file (void);
-static void load_user_pre_image_file (void);
+static const char *user_init_file;
+static const char *user_pre_image_file;
+static const char *site_pre_image_file;
 
 /* Set by command line flag.  When true, Smalltalk saves a snapshot after
    loading the files on the command line, before exiting.  */
 static mst_Boolean snapshot_after_load = false;
 
-/* Whether SMALLTALK_IMAGE is set (only if it is set, .stpre is loaded) */
-static mst_Boolean is_local_image;
-
-/* Usually the same as _gst_image_file_path.  */
-static char *default_image_path;
-
-/* The default_image_path followed by /gst.im */
-static char *default_image_name;
-
 /* If true, skip date checking of kernel files vs. binary image; pretend
    that binary image does not exist.  */
 static mst_Boolean ignore_image = false;
@@ -450,13 +456,13 @@ gst_init_smalltalk (void)
      invoke us.  */
   _gst_smalltalk_initialized = true;
 
-  init_paths ();
   _gst_init_snprintfv ();
 
   result = parse_args (smalltalk_argc, smalltalk_argv);
   if (result)
     return result;
 
+  init_paths ();
   _gst_init_sysdep ();
   _gst_init_signals ();
   _gst_init_cfuncs ();
@@ -479,23 +485,27 @@ gst_init_smalltalk (void)
     loadBinary = abortOnFailure = true;
   else
     {
-      _gst_binary_image_name = default_image_name;
+      char *default_image_file_name;
+      asprintf (&default_image_file_name, "%s/gst.im", _gst_image_file_path);
+
+      _gst_binary_image_name = default_image_file_name;
       loadBinary = !ignore_image && ok_to_load_binary();
       abortOnFailure = false;
 
       /* If we must create a new non-local image, but the directory is
          not writeable, we must resort to the current directory.  In
-         practice this is what is used when working in the build directory.  */
+         practice this is what happens when a "normal user" puts stuff in
+ his ".st" directory and then does "gst -i".  */
 
       if (!loadBinary
-          && !is_local_image
+          && !_gst_is_local_image
           && !_gst_file_is_writeable (_gst_image_file_path))
         {
-          is_local_image = true;
-          xfree (default_image_path);
-          _gst_image_file_path = default_image_path = _gst_get_cur_dir_name ();
+          _gst_is_local_image = true;
+          _gst_image_file_path = _gst_get_cur_dir_name ();
           _gst_binary_image_name = "gst.im";
           loadBinary = !ignore_image && ok_to_load_binary();
+  xfree (default_image_file_name);
         }
     }
 
@@ -538,12 +548,6 @@ gst_init_smalltalk (void)
       _gst_install_initial_methods ();
 
       result = load_standard_files ();
-      if (!result)
- {
-          if (is_local_image)
-    load_user_pre_image_file ();
- }
-
       _gst_regression_testing = willRegressTest;
       if (result)
  return result;
@@ -554,7 +558,8 @@ gst_init_smalltalk (void)
 
   _gst_kernel_initialized = true;
   _gst_invoke_hook ("returnFromSnapshot");
-  load_user_init_file ();
+  if (user_init_file)
+    process_file (user_init_file);
 
   _gst_declare_tracing = traceUserDeclarations;
   _gst_execution_tracing = traceUserExecution;
@@ -569,27 +574,39 @@ gst_init_smalltalk (void)
 void
 gst_top_level_loop (void)
 {
-  int filesProcessed;
-
-  for (filesProcessed = 0; *++smalltalk_argv;)
+  struct loaded_file *file;
+  for (file = loaded_files; file < &loaded_files[n_loaded_files]; file++)
     {
-      if (smalltalk_argv[0][0] == '-')
-        /* - by itself indicates standard input */
+      char *f;
+      if (file->kernel_path)
+ {
+  f = find_kernel_file (file->file_name, "../", LOCAL_BASE_DIR_NAME);
+  if (!f)
+    {
+      _gst_errorf ("Couldn't open kernel file %s", file->file_name);
+      continue;
+    }
+ }
+      else
+ f = xstrdup (file->file_name);
+
+      /* - by itself indicates standard input */
+      if (!strcmp (f, "-"))
         process_stdin ();
       else
  {
-  _gst_use_undeclared++;
-  if (!process_file (smalltalk_argv[0]))
-    _gst_errorf ("Couldn't open file %s", smalltalk_argv[0]);
-
-  _gst_use_undeclared--;
+  if (!process_file (f))
+    _gst_errorf ("Couldn't open file %s", f);
  }
-      filesProcessed++;
+
+      xfree (f);
     }
 
-  if (filesProcessed == 0)
+  if (n_loaded_files == 0)
     process_stdin ();
 
+  xfree (loaded_files);
+  n_loaded_files = 0;
   if (snapshot_after_load)
     _gst_save_to_file (_gst_binary_image_name);
 
@@ -602,43 +619,58 @@ void
 init_paths (void)
 {
   char *currentDirectory = _gst_get_cur_dir_name ();
-  const char *kernel_path, *image_path;
-
-  kernel_path = (char *) getenv ("SMALLTALK_KERNEL");
-  image_path = (char *) getenv ("SMALLTALK_IMAGE");
-  is_local_image = true;
 
-  if (!kernel_path
-      || !_gst_file_is_readable (kernel_path))
+  const char *home = getenv ("HOME");
+  if (home == NULL)
     {
-      char *kernel_file_path;
-      asprintf (&kernel_file_path, "%s/kernel",
-        currentDirectory);
-
-      _gst_kernel_file_path = kernel_file_path;
+      /* By default, apply this kludge so that OSes such as Windows and MS-DOS
+         which have no concept of home directories always load the .stpre file.  */
+      home = currentDirectory;
+      _gst_is_local_image = true;
     }
   else
-    _gst_kernel_file_path = xstrdup (kernel_path);
+    _gst_is_local_image = false;
 
-  if (!image_path
-      || !_gst_file_is_readable (image_path))
-    {
-      image_path = IMAGE_PATH;
+  asprintf ((char **) &_gst_user_kernel_path, "%s/%s", home, LOCAL_BASE_DIR_NAME);
+
+  if (!_gst_kernel_file_path)
+    _gst_kernel_file_path = getenv ("SMALLTALK_KERNEL");
+  if (!_gst_image_file_path)
+    _gst_image_file_path = getenv ("SMALLTALK_IMAGE");
 
-      if (_gst_file_is_readable (image_path))
- /* Found in the standard image path.  Apply this kludge so
-   that OSes such as Windows and MS-DOS which have no concept
-   of home directories always load the .stpre file.  */
- is_local_image = (((char *) getenv ("HOME")) == NULL);
+  if (!_gst_image_file_path
+      || !_gst_file_is_readable (_gst_image_file_path))
+    {
+      if (_gst_file_is_readable (IMAGE_PATH))
+        _gst_image_file_path = IMAGE_PATH;
       else
- image_path = currentDirectory;
+ {
+  _gst_image_file_path = xstrdup (currentDirectory);
+  _gst_is_local_image = true;
+ }
     }
 
-  asprintf (&default_image_name, "%s/gst.im",
-    image_path);
+  if (!_gst_kernel_file_path
+      || !_gst_file_is_readable (_gst_kernel_file_path))
+    {
+      char *default_kernel_file_path;
+      asprintf (&default_kernel_file_path, "%s/kernel", _gst_image_file_path);
+      _gst_kernel_file_path = default_kernel_file_path;
+    }
 
-  _gst_image_file_path = default_image_path = xstrdup (image_path);
   xfree (currentDirectory);
+
+  site_pre_image_file = find_kernel_file (SITE_PRE_IMAGE_FILE_NAME, "../", NULL);
+
+  if (_gst_is_local_image)
+    user_pre_image_file = find_user_file (USER_PRE_IMAGE_FILE_NAME);
+  else
+    user_pre_image_file = NULL;
+
+  if (!_gst_regression_testing)
+    user_init_file = find_user_file (USER_INIT_FILE_NAME);
+  else
+    user_init_file = NULL;
 }
 
 mst_Boolean
@@ -646,7 +678,6 @@ ok_to_load_binary (void)
 {
   time_t imageFileTime;
   const char *fileName;
-  char fullFileName[MAXPATHLEN], *home, preImageFileName[MAXPATHLEN];
 
   imageFileTime = _gst_get_file_modify_time (_gst_binary_image_name);
 
@@ -655,28 +686,20 @@ ok_to_load_binary (void)
 
   for (fileName = standard_files; *fileName; fileName += strlen (fileName) + 1)
     {
-      if (find_kernel_file (fileName, fullFileName)
-  && !is_local_image)
- {
-  /* file lives locally but the image doesn't -- bad semantics.
-     Note that if SOME of the files are local and the image file
-     is local, it is good.  */
-  return (false);
- }
-      if (imageFileTime < _gst_get_file_modify_time (fullFileName))
- return (false);
+      char *fullFileName = find_kernel_file (fileName, "", LOCAL_KERNEL_DIR_NAME);
+      mst_Boolean ok = (imageFileTime > _gst_get_file_modify_time (fullFileName));
+      xfree (fullFileName);
+      if (!ok)
+        return (false);
     }
 
-  if (is_local_image)
-    {
-      if ((home = (char *) getenv ("HOME")) != NULL)
- sprintf (preImageFileName, "%s/%s", home, PRE_IMAGE_FILE_NAME);
-      else
- strcpy (preImageFileName, PRE_IMAGE_FILE_NAME);
+  if (site_pre_image_file
+      && imageFileTime <= _gst_get_file_modify_time (site_pre_image_file))
+    return (false);
 
-      if (imageFileTime < _gst_get_file_modify_time (preImageFileName))
- return (false);
-    }
+  if (user_pre_image_file
+      && imageFileTime <= _gst_get_file_modify_time (user_pre_image_file))
+    return (false);
 
   return (true);
 }
@@ -685,81 +708,81 @@ int
 load_standard_files (void)
 {
   const char *fileName;
-  char fullFileName[MAXPATHLEN];
 
-  _gst_use_undeclared++;
   for (fileName = standard_files; *fileName; fileName += strlen (fileName) + 1)
     {
-      find_kernel_file (fileName, fullFileName);
-      if (!process_file (fullFileName))
+      char *fullFileName = find_kernel_file (fileName, "", LOCAL_KERNEL_DIR_NAME);
+      if (!fullFileName)
  {
   _gst_errorf ("can't find system file '%s'", fullFileName);
-  _gst_errorf
-    ("image bootstrap failed, set SMALLTALK_KERNEL to the directory name");
+  _gst_errorf ("image bootstrap failed, use option --kernel-directory");
   return 1;
  }
+      else
+ {
+  mst_Boolean ok = process_file (fullFileName);
+  xfree (fullFileName);
+  if (!ok)
+    return 1;
+ }
     }
-  _gst_use_undeclared--;
+
+  if (site_pre_image_file)
+    process_file (site_pre_image_file);
+
+  if (user_pre_image_file)
+    process_file (user_pre_image_file);
+
   return 0;
 }
 
 
-mst_Boolean
-find_kernel_file (const char *fileName,
-  char *fullFileName)
-{
-  if (_gst_file_is_readable (fileName))
-    {
-      strcpy (fullFileName, fileName);
-      return (true);
+char *
+find_kernel_file (const char *fileName, const char *systemPrefix,
+  const char *userDir)
+{
+  char *fullFileName, *localFileName;
+
+  asprintf (&fullFileName, "%s/%s%s", _gst_kernel_file_path, systemPrefix,
+    fileName);
+  if (_gst_is_local_image && userDir)
+    {
+      asprintf (&localFileName, "%s/%s/%s", _gst_user_kernel_path, userDir, fileName);
+      if (_gst_file_is_readable (localFileName)
+          /* If the system file is newer, use the system file instead.  */
+          && (!_gst_file_is_readable (fullFileName) ||
+      _gst_get_file_modify_time (localFileName) >=
+      _gst_get_file_modify_time (fullFileName)))
+ {
+  xfree (fullFileName);
+  return localFileName;
+ }
+      else
+ xfree (localFileName);
     }
 
-  sprintf (fullFileName, "%s/%s", _gst_kernel_file_path,
-   fileName);
   if (_gst_file_is_readable (fullFileName))
-    {
-      char systemFileName[256];
-      sprintf (systemFileName, KERNEL_PATH "/%s", fileName);
-      /* If this file and the system file are the same, consider the
-         file as a system file instead.  */
-      return (!_gst_file_is_readable (systemFileName) ||
-      _gst_get_file_modify_time (fullFileName) !=
-      _gst_get_file_modify_time (systemFileName));
-    }
+    return fullFileName;
 
-  sprintf (fullFileName, KERNEL_PATH "/%s", fileName);
-  return (false);
+  xfree (fullFileName);
+  return NULL;
 }
 
 
-void
-load_user_pre_image_file (void)
+char *
+find_user_file (const char *fileName)
 {
-  char fileName[MAXPATHLEN], *home;
-
-  if ((home = (char *) getenv ("HOME")) != NULL)
-    sprintf (fileName, "%s/%s", home, PRE_IMAGE_FILE_NAME);
+  char *fullFileName;
+  asprintf (&fullFileName, "%s/%s", _gst_user_kernel_path, fileName);
+  if (!_gst_file_is_readable (fullFileName))
+    {
+      xfree (fullFileName);
+      return NULL;
+    }
   else
-    strcpy (fileName, PRE_IMAGE_FILE_NAME);
-
-  process_file (fileName);
+    return fullFileName;
 }
 
-void
-load_user_init_file (void)
-{
-  char fileName[MAXPATHLEN], *home;
-
-  if (_gst_regression_testing)
-    return;
-
-  if ((home = (char *) getenv ("HOME")) != NULL)
-    sprintf (fileName, "%s/%s", home, INIT_FILE_NAME);
-  else
-    strcpy (fileName, INIT_FILE_NAME);
-
-  process_file (fileName);
-}
 
 void
 process_stdin ()
@@ -789,9 +812,11 @@ process_file (const char *fileName)
   if (_gst_verbosity > 2)
     printf ("Processing %s\n", fileName);
 
+  _gst_use_undeclared++;
   _gst_push_unix_file (fd, fileName);
   _gst_parse_stream (false);
   _gst_pop_stream (true);
+  _gst_use_undeclared--;
   return (true);
 }
 
@@ -800,7 +825,6 @@ int
 parse_args (int argc,
     const char **argv)
 {
-  const char **av = argv;
   int ch, prev_optind = 1, minus_a_optind = -1;
 
 #ifndef ENABLE_DYNAMIC_TRANSLATION
@@ -809,6 +833,9 @@ parse_args (int argc,
 # define OPTIONS "-acdDf:ghiI:K:lL:pQqrSvV"
 #endif
 
+  loaded_files =
+    (struct loaded_file *) xmalloc (sizeof (struct loaded_file) * argc);
+
   /* get rid of getopt's own error reporting for invalid options */
   opterr = 1;
 
@@ -867,7 +894,8 @@ parse_args (int argc,
  case 'f':
   /* Same as -Q, passing a file, and -a.  */
   _gst_verbosity = 0;
-  *++av = optarg;
+  loaded_files[n_loaded_files].kernel_path = false;
+  loaded_files[n_loaded_files++].file_name = optarg;
 
  case 'a':
   /* "Officially", the C command line ends here.  The Smalltalk
@@ -889,12 +917,17 @@ parse_args (int argc,
   break;
 
  case 'K':
-  {
-    char *file;
-    asprintf (&file, "%s/%s", _gst_image_file_path, optarg);
-    *++av = file;
-    break;
-  }
+  loaded_files[n_loaded_files].kernel_path = true;
+  loaded_files[n_loaded_files++].file_name = optarg;
+  break;
+
+ case OPT_KERNEL_DIR:
+  _gst_kernel_file_path = optarg;
+  break;
+
+ case OPT_IMAGE_DIR:
+  _gst_image_file_path = optarg;
+  break;
 
  case 'v':
   printf (copyright_and_legal_stuff_text, VERSION, KERNEL_PATH,
@@ -902,7 +935,8 @@ parse_args (int argc,
   return -1;
 
  case '\1':
-  *++av = optarg;
+  loaded_files[n_loaded_files].kernel_path = false;
+  loaded_files[n_loaded_files++].file_name = optarg;
   break;
 
  default:
@@ -927,7 +961,8 @@ parse_args (int argc,
      is nothing after -a, or if we finished processing the argument
      which included -a, leave.  */
   _gst_smalltalk_passed_argc = argc - optind;
-  _gst_smalltalk_passed_argv = xmalloc (sizeof (char *) * _gst_smalltalk_passed_argc);
+  _gst_smalltalk_passed_argv =
+    xmalloc (sizeof (char *) * _gst_smalltalk_passed_argc);
   memcpy (_gst_smalltalk_passed_argv, argv + optind,
   sizeof (char *) * _gst_smalltalk_passed_argc);
   break;
@@ -936,6 +971,5 @@ parse_args (int argc,
       prev_optind = optind;
     }
 
-  *++av = NULL;
   return 0;
 }


--- orig/libgst/lib.h
+++ mod/libgst/lib.h
@@ -62,6 +62,13 @@ extern const char *_gst_kernel_file_path
 extern const char *_gst_image_file_path
   ATTRIBUTE_HIDDEN;
 
+/* The ".st" directory, in the current directory or in the user's
+   home directory.  */
+extern const char *_gst_user_kernel_path;
+
+/* Whether the image is global or per-user.  */
+extern mst_Boolean _gst_is_local_image;
+
 /* This is the name of the binary image to load.  If it is not NULL after the
    command line is parsed, the checking of the dates of the kernel source files
    against the image file date is overridden.  If it is NULL, it is set to


--- orig/scripts/Finish.st
+++ mod/scripts/Finish.st
@@ -41,14 +41,16 @@ ok ifFalse: [ ObjectMemory quit: 1 ]!
 
 "Symbol rebuildTable."
 
-"Remove DESTDIR from the paths stored in the image"
+"Remove DESTDIR and references to the build directory, from the paths
+ stored in the image"
 | old new |
 old := Smalltalk arguments first.
 new := Smalltalk arguments at: 2.
 old = new ifFalse: [ FileSegment relocateFrom: old to: new ].
 ImageFileName := 'gst.im'.
+ImageLocal := false.
 ImageFilePath := new.
-KernelFileLocalPath := new, '/kernel'.
-KernelFilePath := new, '/kernel'!
+KernelFilePath := new, '/kernel'.
+KernelFileUserPath := nil!
 
 ObjectMemory snapshot!


--- orig/tests/Makefile.am
+++ mod/tests/Makefile.am
@@ -109,8 +109,7 @@ EXTRA_DIST = run-test
  done
 
 gst.im: ../kernel/stamp-classes AnsiLoad.st Ansi.st AnsiDB.st
- cp ../gst.im .
- builddir=`pwd` && \
+ cp $(top_builddir)/gst.im .
  cd $(srcdir) && \
- $$builddir/../gst -QSI $$builddir/gst.im AnsiLoad.st
+  @abs_top_builddir@/gst -SI @abs_top_builddir@/tests/gst.im AnsiLoad.st
 




_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] handle paths in a saner way

Mike Anderson-3
Paolo Bonzini wrote:

> I started implementing the --kernel-directory and --image-directory
> options, but I got carried away and ended up reimplementing a lot of the
> startup sequence, and in particular the way kernel files are looked up.
>  This had interesting ramifications.
>
> The changes can be summed up like this:
>
> - the `~/.stinit' and `~/.stpre' files are now named `~/.st/init.st' and
> `~/.st/pre.st'
>
> - files requested with the `-K' command-line option are sought for in
> the `~/.st' directory too
>
> - kernel files may be overridden by placing them in `.st/kernel'; they
> will be used when you do `gst -i' but you cannot write to
> `/usr/local/share/smalltalk'
>
> - a site-wide customization file can be placed in
> `/usr/local/share/smalltalk/site-pre.st'.  It will be loaded whenever
> users create images with `gst -i', before the snapshot and before the
> `~/.st/pre.st' file.

I don't create new images - I always copy the image file. Is that a bad
idea?

> - the kernel path is stored in the image when it's created; it's not
> changed when the image is loaded.  In addition, `Directory systemKernel'
> and `Directory localKernel' are not used anymore, and just return the
> same as `Directory kernel'.
>
> - Smalltalk programs have access to the aforementioned `~/.st' directory
> as `Directory userKernel' (name subject to change).  A `packages.xml'
> file can be put in the directory too -- I like this a lot.

I'm not sure if I've said this before, but I'm greatly in favour of
having a search path for package files. The user (well, me, anyway) is
likely to have packages that fall into a number of categories. In
particular, packages that they have written themselves and unstable
versions of those packages.

For example, I have an applet on my desktop that shows a clock. This
requires a package which provides access to the Cairo library. If I am
developing another application that requires changes to that library, I
want that to use a different set of code so that the clock does not
crash. On the other hand, I don't want to duplicate the other standard
libraries I have written - if I upgrade them, I want all of my
applications to pick up the changes.

Also, why XML, when we don't even have an XML parser in the standard
libraries? (OK, I know I've said that before).

> Now, apart from scrutinizing the code (which I'll appreciate), I'm
> looking for:
>
> - alternative names for `Directory userKernel', which is really `~/.st';
>  I thought of `Directory userRoot' but I don't really like it;
>
> - if you don't like the semantics (details are in the manual, in the
> Startup Sequence node), suggestions on how to improve them;

I have read through this (I had never noticed it before!). It suggests
that the image is rebuilt if it is older than any of the kernel files. I
presume that doesn't happen if -I is given, but it doesn't say that.

Whilst kind of nice, I'm not too keen on the automatic building of the
image in the first place. I'd rather manually rebuild it when I change
the kernel source. Under what circumstances will you have a gst
executable but no valid image? Also, it takes time to check the kernel
files, no?

It's not clear what is done with .stpre, but I guess that "If the image
lies in the current directory, or if at least a kernel file was found
outside of the system default path, a user-dependant `.stpre'(1)" should
end with "is also loaded".

> - whether root (or any other user who can write to /usr/local/share)
> should be forbidden from having a ~/.st directory;

The implication is that the .stpre and .stinit of that user would be
built into the new image that is written to /usr/local/share? That
doesn't sound like a good idea, not least because #methodSourceString
will be broken. However, I don't think that that means they shouldn't be
able to have local packages in ~/.st.

> - whether `~/.st/init.st' makes sense at all; I'm inclined to remove it;

I don't think it makes sense.

Mike


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] handle paths in a saner way

Paolo Bonzini

> I don't create new images - I always copy the image file. Is that a bad
> idea?

No, absolutely.  But the .stpre or .st/pre.st file is a good place to
put bug fixes in, for example.

Another thing to put in the file could be this:

(FileStream open: Directory image, '/pre.st' mode: 'r' ifFail: [ ^self ])
     fileIn

which is a little dangerous to do by default, but could be useful to a
user that wants to load different packages in different default images
(so he will put a "fileInPackages:" in the image directory's pre.st file).

It must be said also that working with environment variables is kind of
verbose/uncommon.  Using something like --image-directory would be simpler.

>> - Smalltalk programs have access to the aforementioned `~/.st' directory
>> as `Directory userKernel' (name subject to change).  A `packages.xml'
>> file can be put in the directory too -- I like this a lot.
>
> I'm not sure if I've said this before, but I'm greatly in favour of
> having a search path for package files. The user (well, me, anyway) is
> likely to have packages that fall into a number of categories. In
> particular, packages that they have written themselves and unstable
> versions of those packages.

Well, for this, remember that a `packages.xml' file can be put in the
image directory too, and source files will only be sought relative to
that directory.

One could have, then, aliases such as

   alias gstdev=gst --image-dir=$HOME/gst-devel

This would:

1) rebuild the image when you modified "global" stuff in ~/.st (as I
said before, with bugfixes etc.)

2) allow you to use package descriptions from $HOME/gst-devel/packages.xml


In general, however, I agree that it would be best to have source and
package description in the same file, possibly a ZIP file like Java's
JARs.  Note that in this case the `packages.xml' file would not die, it
would just be in the ZIP file.

> Also, why XML, when we don't even have an XML parser in the standard
> libraries? (OK, I know I've said that before).

Just because.  XML is easily extensible (remember when we added
<namespace> to packages.xml) and any other syntax would not be much
easier to parse (e.g. JSON).

The obvious exception may be Smalltalk code, but in the case of ZIP
files I mentioned above, one may not want to evaluate user code lightly
if they care about security.

>> - if you don't like the semantics (details are in the manual, in the
>> Startup Sequence node), suggestions on how to improve them;
>
> I have read through this (I had never noticed it before!). It suggests
> that the image is rebuilt if it is older than any of the kernel files. I
> presume that doesn't happen if -I is given, but it doesn't say that.

I think it says that in the -I option description.  I should say "this
section does not apply if -I is used".

> Whilst kind of nice, I'm not too keen on the automatic building of the
> image in the first place. I'd rather manually rebuild it when I change
> the kernel source. Under what circumstances will you have a gst
> executable but no valid image?

As hinted above, this would happen if you put files in ~/.st/kernel for
example.  Then gst would notice the new files and make a new image.

> Also, it takes time to check the kernel files, no?

Yes, but this is for the user's experimenting, not for deployment where
anyway you'd use -I or even an executable image file (chmod +x).

> It's not clear what is done with .stpre, but I guess that "If the image
> lies in the current directory, or if at least a kernel file was found
> outside of the system default path, a user-dependant `.stpre'(1)" should
> end with "is also loaded".

Indeed.

>> - whether root (or any other user who can write to /usr/local/share)
>> should be forbidden from having a ~/.st directory;
>
> The implication is that the .stpre and .stinit of that user would be
> built into the new image that is written to /usr/local/share? That
> doesn't sound like a good idea, not least because #methodSourceString
> will be broken. However, I don't think that that means they shouldn't be
> able to have local packages in ~/.st.

I've now added a --no-user-files option that is used during the build.

>> - whether `~/.st/init.st' makes sense at all; I'm inclined to remove it;
>
> I don't think it makes sense.

Yes.  Though the problems it has are mitigated by the --no-user-files
option, and the code to support it is just a handful of lines.

Thanks for the suggestions!

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] handle paths in a saner way

Mike Anderson-3
Paolo Bonzini wrote:

>
>> Also, why XML, when we don't even have an XML parser in the standard
>> libraries? (OK, I know I've said that before).
>
> Just because.  XML is easily extensible (remember when we added
> <namespace> to packages.xml) and any other syntax would not be much
> easier to parse (e.g. JSON).
>
> The obvious exception may be Smalltalk code, but in the case of ZIP
> files I mentioned above, one may not want to evaluate user code lightly
> if they care about security.

The thing is, XML is not that easy to parse, and, in fact, packages.xml
is not parsed properly - the parsing is done line by line, and can't
handle comments. What's really spurring this mini-rant is that I've been
looking for a decent XML editor recently, and there aren't any. That
tells you something.

Mike


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: [RFC] handle paths in a saner way

Paolo Bonzini

> The thing is, XML is not that easy to parse, and, in fact, packages.xml
> is not parsed properly - the parsing is done line by line, and can't
> handle comments. What's really spurring this mini-rant is that I've been
> looking for a decent XML editor recently, and there aren't any. That
> tells you something.

I can only agree, but this is a somewhat separate issue.

For 2.4 I may add a smallish and more compliant XML/SAX parser.  Do you
have any alternatives?

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Re: [RFC] handle paths in a saner way

Stefan Schmiedl
Paolo Bonzini (09.02. 09:51):

>
> >The thing is, XML is not that easy to parse, and, in fact, packages.xml
> >is not parsed properly - the parsing is done line by line, and can't
>
> I can only agree, but this is a somewhat separate issue.
>
> For 2.4 I may add a smallish and more compliant XML/SAX parser.  Do you
> have any alternatives?

how about using the "simple" ini-file known on windoze?

[packagename]
attr=value
attr=value
attr=value
attr=value

Easy and quick to parse for non-nested structures as you have
in packages.xml

s.


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Re: [RFC] handle paths in a saner way

Mike Anderson-3
In reply to this post by Paolo Bonzini
Paolo Bonzini wrote:

>
>> The thing is, XML is not that easy to parse, and, in fact, packages.xml
>> is not parsed properly - the parsing is done line by line, and can't
>> handle comments. What's really spurring this mini-rant is that I've been
>> looking for a decent XML editor recently, and there aren't any. That
>> tells you something.
>
> I can only agree, but this is a somewhat separate issue.
>
> For 2.4 I may add a smallish and more compliant XML/SAX parser.  Do you
> have any alternatives?

I have this one:
http://www.friendofthepigeon.co.uk/wordpress/wp-content/naivexml.tgz
(XMLParser.st & Handler.st)

It's deliberately simple, does a few things wrong (mostly deliberately),
and has some bits missing, like support for CDATA sections (I disapprove
of CDATA sections), but it works well. I wrote it as an alternative for
the full XML package, which is hard going and can't cope if there's no
prolog (horrors!).

I'd quite like to see the packages file written as a (large) array
constant, actually, but to make it attractive, the parser needs to allow
symbols without the # prefix (as opposed to just true, false and nil).
That's quite high up my wish-list for general programming, actually.

Regards,

Mike


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Re: [RFC] handle paths in a saner way

Paolo Bonzini
> I have this one:
> http://www.friendofthepigeon.co.uk/wordpress/wp-content/naivexml.tgz
> (XMLParser.st & Handler.st)

Looks pretty good!  Thanks!

> It's deliberately simple, does a few things wrong (mostly deliberately),
> and has some bits missing, like support for CDATA sections (I disapprove
> of CDATA sections), but it works well.

Ok, we can live without CDATA. :-)

Replying to other suggestions, flat files are not really the best
solution.  For example, I can very well see something like:

<package>
   <name>XYZ</name>
   ...
   <filein>XYZ.st</filein>
   <tests>
     <script>XYZTest.*</script>
     <filein>tests/XYZ.st</filein>
   </tests>
</package>


Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk